<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 report_func = &mut |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, report_func);
                    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,
    state_stack: Vec<NodeState>,
    reported_nodes: NodeCount,
    unreported_nodes: NodeCount,
    report_func: &'a mut FnMut(NodeCount) -> Result<(), TerminatedSearch>,
}

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

    // 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_func)(self.reported_nodes));
        }
        Ok(())
    }

    #[inline]
    pub fn reset(&mut self) {
        self.moves.clear();
        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 mut search = Search {
            tt: &TranspositionTable::new(),
            position: p,
            moves: &mut MoveStack::new(),
            state_stack: vec![],
            reported_nodes: 0,
            unreported_nodes: 0,
            report_func: &mut |_| Ok(()),
        };
        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>beautifications<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.
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,
    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> {
        Search {
            tt: tt,
            position: position,
            moves: moves,
            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) {
        self.moves.clear();
        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);
    }
}
<|endoftext|>


<commit_before>use std::borrow::BorrowMut;

use basic::{Encoding, Type};
use errors::{Result, ParquetError};
use schema::types::Type as SchemaType;
use parquet_thrift::parquet::{ColumnChunk, ColumnMetaData};

pub struct ParquetMetaData {
  file_metadata: FileMetaData,
  row_groups: Vec<RowGroupMetaData>
}

/// Metadata for a Parquet file
pub struct FileMetaData {
  version: i32,
  num_rows: i64,
  created_by: Option<String>,
  schema: Box<SchemaType>
}

impl FileMetaData {
  pub fn new(version: i32, num_rows: i64, created_by: Option<String>,
             schema: Box<SchemaType>) -> Self {
    FileMetaData { version, num_rows, created_by, schema }
  }

  pub fn version(&self) -> i32 {
    self.version
  }

  pub fn num_rows(&self) -> i64 {
    self.num_rows
  }

  pub fn created_by(&self) -> &Option<String> {
    &self.created_by
  }

  pub fn schema(&mut self) -> &mut SchemaType {
    self.schema.borrow_mut()
  }
}

/// Metadata for a row group
pub struct RowGroupMetaData {
  columns: Vec<Box<ColumnChunkMetaData>>,
  num_rows: i64,
  total_byte_size: i64,
  path: String
}

// Metadata for a column chunk
pub struct ColumnChunkMetaData {
  column_type: Type,
  column_path: ColumnPath,
  encodings: Vec<Encoding>,
  file_path: Option<String>,
  file_offset: i64,
  num_values: i64,
  total_compressed_size: i64,
  total_uncompressed_size: i64,
  data_page_offset: i64,
  index_page_offset: Option<i64>,
  dictionary_page_offset: Option<i64>
}

/// Represents common operations for a column chunk
impl ColumnChunkMetaData {
  /// File where the column chunk is stored. If not set, assumed to
  /// be at the same file as the metadata.
  /// This path is relative to the current file.
  pub fn file_path(&self) -> &Option<String> {
    &self.file_path
  }

  /// Byte offset in `file_path()`.
  pub fn file_offset(&self) -> i64 {
    self.file_offset
  }

  /// Type of this column. Must be primitive.
  pub fn column_type(&self) -> Type {
    self.column_type
  }

  /// Path (or identifier) of this column
  pub fn column_path(&self) -> &ColumnPath {
    &self.column_path
  }

  /// All encodings used for this column
  pub fn encodings(&self) -> &Vec<Encoding> {
    &self.encodings
  }

  /// TODO: add codec

  /// Total number of values in this column chunk
  pub fn num_values(&self) -> i64 {
    self.num_values
  }

  /// Get the total compressed data size of this column chunk
  fn compressed_size(&self) -> i64 {
    self.total_compressed_size
  }

  /// Get the total uncompressed data size of this column chunk
  fn uncompressed_size(&self) -> i64 {
    self.total_uncompressed_size
  }

  /// Get the offset for the column data
  fn data_page_offset(&self) -> i64 {
    self.data_page_offset
  }

  /// Whether this column chunk contains a dictionary page
  fn has_dictionary_page(&self) -> bool {
    self.dictionary_page_offset.is_some()
  }

  /// TODO: add statistics

  /// Get the offset for the dictionary page, if any
  fn dictionary_page_offset(&self) -> Option<i64> {
    self.dictionary_page_offset.clone()
  }

  /// Conversion from Thrift
  pub fn from_thrift(cc: ColumnChunk) -> Result<Self> {
    if cc.meta_data.is_none() {
      return Err(schema_err!("Expected to have column metadata"))
    }
    let mut col_metadata: ColumnMetaData = cc.meta_data.unwrap();
    let column_type = Type::from(col_metadata.type_);
    let column_path = ColumnPath::new(col_metadata.path_in_schema);
    let encodings = col_metadata.encodings.drain(0..).map(Encoding::from).collect();
    let file_path = cc.file_path;
    let file_offset = cc.file_offset;
    let num_values = col_metadata.num_values;
    let total_compressed_size = col_metadata.total_compressed_size;
    let total_uncompressed_size = col_metadata.total_uncompressed_size;
    let data_page_offset = col_metadata.data_page_offset;
    let index_page_offset = col_metadata.index_page_offset;
    let dictionary_page_offset = col_metadata.dictionary_page_offset;
    let result = ColumnChunkMetaData
    { column_type, column_path, encodings, file_path,
      file_offset, num_values, total_compressed_size, total_uncompressed_size,
      data_page_offset, index_page_offset, dictionary_page_offset };
    Ok(result)
  }
}

/// Represents a path in a nested schema
pub struct ColumnPath {
  parts: Vec<String>
}

impl ColumnPath {
  pub fn new(parts: Vec<String>) -> Self {
    ColumnPath { parts: parts }
  }
}
<commit_msg>Add from_thrift for RowGroupMetaData<commit_after>use std::borrow::BorrowMut;

use basic::{Encoding, Type};
use errors::{Result, ParquetError};
use schema::types::Type as SchemaType;
use parquet_thrift::parquet::{ColumnChunk, ColumnMetaData, RowGroup};

pub struct ParquetMetaData {
  file_metadata: FileMetaData,
  row_groups: Vec<RowGroupMetaData>
}

/// Metadata for a Parquet file
pub struct FileMetaData {
  version: i32,
  num_rows: i64,
  created_by: Option<String>,
  schema: Box<SchemaType>
}

impl FileMetaData {
  pub fn new(version: i32, num_rows: i64, created_by: Option<String>,
             schema: Box<SchemaType>) -> Self {
    FileMetaData { version, num_rows, created_by, schema }
  }

  pub fn version(&self) -> i32 {
    self.version
  }

  pub fn num_rows(&self) -> i64 {
    self.num_rows
  }

  pub fn created_by(&self) -> &Option<String> {
    &self.created_by
  }

  pub fn schema(&mut self) -> &mut SchemaType {
    self.schema.borrow_mut()
  }
}

/// Metadata for a row group
pub struct RowGroupMetaData {
  columns: Vec<ColumnChunkMetaData>,
  num_rows: i64,
  total_byte_size: i64
}

impl RowGroupMetaData {
  pub fn num_columns(&self) -> usize {
    self.columns.len()
  }

  pub fn column(&self, i: usize) -> &ColumnChunkMetaData {
    &self.columns[i]
  }

  pub fn num_rows(&self) -> i64 {
    self.num_rows
  }

  pub fn total_byte_size(&self) -> i64 {
    self.total_byte_size
  }

  pub fn from_thrift(rg: RowGroup) -> Result<RowGroupMetaData> {
    let total_byte_size = rg.total_byte_size;
    let num_rows = rg.num_rows;
    let mut columns = Vec::new();
    for c in rg.columns {
      columns.push(ColumnChunkMetaData::from_thrift(c)?)
    }
    Ok(RowGroupMetaData{columns, num_rows, total_byte_size})
  }
}

// Metadata for a column chunk
pub struct ColumnChunkMetaData {
  column_type: Type,
  column_path: ColumnPath,
  encodings: Vec<Encoding>,
  file_path: Option<String>,
  file_offset: i64,
  num_values: i64,
  total_compressed_size: i64,
  total_uncompressed_size: i64,
  data_page_offset: i64,
  index_page_offset: Option<i64>,
  dictionary_page_offset: Option<i64>
}

/// Represents common operations for a column chunk
impl ColumnChunkMetaData {
  /// File where the column chunk is stored. If not set, assumed to
  /// be at the same file as the metadata.
  /// This path is relative to the current file.
  pub fn file_path(&self) -> &Option<String> {
    &self.file_path
  }

  /// Byte offset in `file_path()`.
  pub fn file_offset(&self) -> i64 {
    self.file_offset
  }

  /// Type of this column. Must be primitive.
  pub fn column_type(&self) -> Type {
    self.column_type
  }

  /// Path (or identifier) of this column
  pub fn column_path(&self) -> &ColumnPath {
    &self.column_path
  }

  /// All encodings used for this column
  pub fn encodings(&self) -> &Vec<Encoding> {
    &self.encodings
  }

  /// TODO: add codec

  /// Total number of values in this column chunk
  pub fn num_values(&self) -> i64 {
    self.num_values
  }

  /// Get the total compressed data size of this column chunk
  fn compressed_size(&self) -> i64 {
    self.total_compressed_size
  }

  /// Get the total uncompressed data size of this column chunk
  fn uncompressed_size(&self) -> i64 {
    self.total_uncompressed_size
  }

  /// Get the offset for the column data
  fn data_page_offset(&self) -> i64 {
    self.data_page_offset
  }

  /// Whether this column chunk contains a dictionary page
  fn has_dictionary_page(&self) -> bool {
    self.dictionary_page_offset.is_some()
  }

  /// TODO: add statistics

  /// Get the offset for the dictionary page, if any
  fn dictionary_page_offset(&self) -> Option<i64> {
    self.dictionary_page_offset.clone()
  }

  /// Conversion from Thrift
  pub fn from_thrift(cc: ColumnChunk) -> Result<Self> {
    if cc.meta_data.is_none() {
      return Err(schema_err!("Expected to have column metadata"))
    }
    let mut col_metadata: ColumnMetaData = cc.meta_data.unwrap();
    let column_type = Type::from(col_metadata.type_);
    let column_path = ColumnPath::new(col_metadata.path_in_schema);
    let encodings = col_metadata.encodings.drain(0..).map(Encoding::from).collect();
    let file_path = cc.file_path;
    let file_offset = cc.file_offset;
    let num_values = col_metadata.num_values;
    let total_compressed_size = col_metadata.total_compressed_size;
    let total_uncompressed_size = col_metadata.total_uncompressed_size;
    let data_page_offset = col_metadata.data_page_offset;
    let index_page_offset = col_metadata.index_page_offset;
    let dictionary_page_offset = col_metadata.dictionary_page_offset;
    let result = ColumnChunkMetaData
    { column_type, column_path, encodings, file_path,
      file_offset, num_values, total_compressed_size, total_uncompressed_size,
      data_page_offset, index_page_offset, dictionary_page_offset };
    Ok(result)
  }
}

/// Represents a path in a nested schema
pub struct ColumnPath {
  parts: Vec<String>
}

impl ColumnPath {
  pub fn new(parts: Vec<String>) -> Self {
    ColumnPath { parts: parts }
  }
}
<|endoftext|>


<commit_before>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Worker that runs in a virtio-video thread.

use std::collections::{BTreeMap, VecDeque};

use sys_util::{error, EventFd, PollContext};
use vm_memory::GuestMemory;

use crate::virtio::queue::{DescriptorChain, Queue};
use crate::virtio::resource_bridge::ResourceRequestSocket;
use crate::virtio::video::command::{QueueType, VideoCmd};
use crate::virtio::video::device::{
    AsyncCmdTag, Device, Token, VideoCmdResponseType, VideoEvtResponseType,
};
use crate::virtio::video::error::{VideoError, VideoResult};
use crate::virtio::video::event::{self, EvtType, VideoEvt};
use crate::virtio::video::protocol;
use crate::virtio::video::response::{self, CmdResponse, Response};
use crate::virtio::video::{Error, Result};
use crate::virtio::{Interrupt, Reader, Writer};

pub struct Worker {
    pub interrupt: Interrupt,
    pub mem: GuestMemory,
    pub cmd_evt: EventFd,
    pub event_evt: EventFd,
    pub kill_evt: EventFd,
    pub resource_bridge: ResourceRequestSocket,
}

/// BTreeMap which stores descriptor chains in which asynchronous responses will be written.
type DescPool<'a> = BTreeMap<AsyncCmdTag, DescriptorChain<'a>>;
/// Pair of a descriptor chain and a response to be written.
type WritableResp<'a> = (DescriptorChain<'a>, VideoResult<response::CmdResponse>);

/// Invalidates all pending asynchronous commands in a given `DescPool` value and returns an updated
/// `DescPool` value and a list of `WritableResp` to be sent to the guest.
fn cancel_pending_requests<'a>(
    s_id: u32,
    desc_pool: DescPool<'a>,
) -> (DescPool<'a>, Vec<WritableResp<'a>>) {
    let mut new_desc_pool: DescPool<'a> = Default::default();
    let mut resps = vec![];

    for (key, value) in desc_pool.into_iter() {
        match key {
            AsyncCmdTag::Queue { stream_id, .. } if stream_id == s_id => {
                resps.push((
                    value,
                    Ok(CmdResponse::ResourceQueue {
                        timestamp: 0,
                        flags: protocol::VIRTIO_VIDEO_BUFFER_FLAG_ERR,
                        size: 0,
                    }),
                ));
            }
            AsyncCmdTag::Drain { stream_id } | AsyncCmdTag::Clear { stream_id, .. }
                if stream_id == s_id =>
            {
                // TODO(b/1518105): Use more appropriate error code if a new protocol supports one.
                resps.push((value, Err(VideoError::InvalidOperation)));
            }
            AsyncCmdTag::Queue { .. } | AsyncCmdTag::Drain { .. } | AsyncCmdTag::Clear { .. } => {
                // Keep commands for other streams.
                new_desc_pool.insert(key, value);
            }
        }
    }

    (new_desc_pool, resps)
}

impl Worker {
    /// Writes responses into the command queue.
    fn write_responses<'a>(
        &self,
        cmd_queue: &mut Queue,
        responses: &mut VecDeque<WritableResp>,
    ) -> Result<()> {
        let mut needs_interrupt_commandq = false;
        // Write responses into command virtqueue.
        while let Some((desc, resp)) = responses.pop_front() {
            let desc_index = desc.index;
            let mut writer = Writer::new(&self.mem, desc).map_err(Error::InvalidDescriptorChain)?;
            match resp {
                Ok(r) => {
                    if let Err(e) = r.write(&mut writer) {
                        error!("failed to write an OK response for {:?}: {}", r, e);
                    }
                }
                Err(err) => {
                    if let Err(e) = err.write(&mut writer) {
                        error!("failed to write an Error response for {:?}: {}", err, e);
                    }
                }
            }

            cmd_queue.add_used(&self.mem, desc_index, writer.bytes_written() as u32);
            needs_interrupt_commandq = true;
        }
        if needs_interrupt_commandq {
            self.interrupt.signal_used_queue(cmd_queue.vector);
        }
        Ok(())
    }

    /// Writes a `VideoEvt` into the event queue.
    fn write_event(&self, event_queue: &mut Queue, event: &mut event::VideoEvt) -> Result<()> {
        let desc = event_queue
            .peek(&self.mem)
            .ok_or_else(|| Error::DescriptorNotAvailable)?;
        event_queue.pop_peeked(&self.mem);

        let desc_index = desc.index;
        let mut writer = Writer::new(&self.mem, desc).map_err(Error::InvalidDescriptorChain)?;
        event
            .write(&mut writer)
            .map_err(|error| Error::WriteEventFailure {
                event: event.clone(),
                error,
            })?;
        event_queue.add_used(&self.mem, desc_index, writer.bytes_written() as u32);
        self.interrupt.signal_used_queue(event_queue.vector);
        Ok(())
    }

    /// Handles a `DescriptorChain` value sent via the command queue and returns an updated
    /// `DescPool` and `VecDeque` of `WritableResp` to be sent to the guest.
    fn handle_command_desc<'a, T: Device>(
        &'a self,
        device: &mut T,
        poll_ctx: &PollContext<Token>,
        mut desc_pool: DescPool<'a>,
        desc: DescriptorChain<'a>,
    ) -> Result<(DescPool<'a>, VecDeque<WritableResp<'a>>)> {
        let mut resps: VecDeque<WritableResp> = Default::default();
        let mut reader =
            Reader::new(&self.mem, desc.clone()).map_err(Error::InvalidDescriptorChain)?;

        let cmd = VideoCmd::from_reader(&mut reader).map_err(Error::ReadFailure)?;

        // If a destruction command comes, cancel pending requests.
        match cmd {
            VideoCmd::ResourceDestroyAll { stream_id } | VideoCmd::StreamDestroy { stream_id } => {
                let (next_desc_pool, rs) = cancel_pending_requests(stream_id, desc_pool);
                desc_pool = next_desc_pool;
                resps.append(&mut Into::<VecDeque<_>>::into(rs));
            }
            _ => (),
        };

        // Process the command by the device.
        let resp = device.process_cmd(cmd, &poll_ctx, &self.resource_bridge);

        match resp {
            Ok(VideoCmdResponseType::Sync(r)) => {
                resps.push_back((desc.clone(), Ok(r)));
            }
            Ok(VideoCmdResponseType::Async(tag)) => {
                // If the command expects an asynchronous response,
                // store `desc` to use it after the back-end device notifies the
                // completion.
                desc_pool.insert(tag, desc);
            }
            Err(e) => {
                resps.push_back((desc.clone(), Err(e)));
            }
        }

        Ok((desc_pool, resps))
    }

    /// Handles the command queue returns an updated `DescPool`.
    fn handle_command_queue<'a, T: Device>(
        &'a self,
        cmd_queue: &mut Queue,
        device: &mut T,
        poll_ctx: &PollContext<Token>,
        mut desc_pool: DescPool<'a>,
    ) -> Result<DescPool<'a>> {
        let _ = self.cmd_evt.read();

        while let Some(desc) = cmd_queue.pop(&self.mem) {
            let (next_desc_pool, mut resps) =
                self.handle_command_desc(device, poll_ctx, desc_pool, desc)?;
            desc_pool = next_desc_pool;
            self.write_responses(cmd_queue, &mut resps)?;
        }
        Ok(desc_pool)
    }

    /// Handles a `VideoEvtResponseType` value and returns an updated `DescPool` and `VecDeque` of
    /// `WritableResp` to be sent to the guest.
    fn handle_event_resp<'a, T: Device>(
        &'a self,
        event_queue: &mut Queue,
        device: &mut T,
        mut desc_pool: DescPool<'a>,
        resp: VideoEvtResponseType,
    ) -> Result<(DescPool<'a>, VecDeque<WritableResp>)> {
        let mut responses: VecDeque<WritableResp> = Default::default();
        match resp {
            VideoEvtResponseType::AsyncCmd {
                tag: AsyncCmdTag::Drain { stream_id },
                resp,
            } => {
                let tag = AsyncCmdTag::Drain { stream_id };
                let drain_desc = desc_pool
                    .remove(&tag)
                    .ok_or_else(|| Error::UnexpectedResponse(tag))?;

                // When `Drain` request is completed, returns an empty output resource
                // with EOS flag first.
                let resource_id = device
                    .take_resource_id_to_notify_eos(stream_id)
                    .ok_or_else(|| Error::NoEOSBuffer { stream_id })?;

                let q_desc = desc_pool
                    .remove(&AsyncCmdTag::Queue {
                        stream_id,
                        queue_type: QueueType::Output,
                        resource_id,
                    })
                    .ok_or_else(|| Error::InvalidEOSResource {
                        stream_id,
                        resource_id,
                    })?;

                responses.push_back((
                    q_desc,
                    Ok(CmdResponse::ResourceQueue {
                        timestamp: 0,
                        flags: protocol::VIRTIO_VIDEO_BUFFER_FLAG_EOS,
                        size: 0,
                    }),
                ));

                // Then, responds the Drain request.
                responses.push_back((drain_desc, resp));
            }
            VideoEvtResponseType::AsyncCmd {
                tag:
                    AsyncCmdTag::Clear {
                        queue_type,
                        stream_id,
                    },
                resp,
            } => {
                let tag = AsyncCmdTag::Clear {
                    queue_type,
                    stream_id,
                };
                let desc = desc_pool
                    .remove(&tag)
                    .ok_or_else(|| Error::UnexpectedResponse(tag))?;

                // When `Clear` request is completed, invalidate all pending requests.
                let (next_desc_pool, resps) = cancel_pending_requests(stream_id, desc_pool);
                desc_pool = next_desc_pool;
                responses.append(&mut Into::<VecDeque<_>>::into(resps));

                // Then, responds the `Clear` request.
                responses.push_back((desc, resp));
            }
            VideoEvtResponseType::AsyncCmd { tag, resp } => {
                let desc = desc_pool
                    .remove(&tag)
                    .ok_or_else(|| Error::UnexpectedResponse(tag))?;
                responses.push_back((desc, resp));
            }
            VideoEvtResponseType::Event(mut evt) => {
                self.write_event(event_queue, &mut evt)?;
            }
        };
        Ok((desc_pool, responses))
    }

    /// Handles an event notified via an event FD and returns an updated `DescPool`.
    fn handle_event_fd<'a, T: Device>(
        &'a self,
        cmd_queue: &mut Queue,
        event_queue: &mut Queue,
        device: &mut T,
        desc_pool: DescPool<'a>,
        stream_id: u32,
    ) -> Result<DescPool<'a>> {
        let resp = device.process_event_fd(stream_id);
        match resp {
            Some(r) => match self.handle_event_resp(event_queue, device, desc_pool, r) {
                Ok((updated_desc_pool, mut resps)) => {
                    self.write_responses(cmd_queue, &mut resps)?;
                    Ok(updated_desc_pool)
                }
                Err(e) => {
                    // Ignore result of write_event for a fatal error.
                    let _ = self.write_event(
                        event_queue,
                        &mut VideoEvt {
                            typ: EvtType::Error,
                            stream_id,
                        },
                    );
                    Err(e)
                }
            },
            None => Ok(desc_pool),
        }
    }

    pub fn run<T: Device>(
        &mut self,
        mut cmd_queue: Queue,
        mut event_queue: Queue,
        mut device: T,
    ) -> Result<()> {
        let poll_ctx: PollContext<Token> = PollContext::build_with(&[
            (&self.cmd_evt, Token::CmdQueue),
            (&self.event_evt, Token::EventQueue),
            (&self.kill_evt, Token::Kill),
            (self.interrupt.get_resample_evt(), Token::InterruptResample),
        ])
        .map_err(Error::PollContextCreationFailed)?;

        // Stores descriptors in which responses for asynchronous commands will be written.
        let mut desc_pool: DescPool<'_> = Default::default();

        loop {
            let poll_events = poll_ctx.wait().map_err(Error::PollError)?;

            for poll_event in poll_events.iter_readable() {
                match poll_event.token() {
                    Token::CmdQueue => {
                        desc_pool = self.handle_command_queue(
                            &mut cmd_queue,
                            &mut device,
                            &poll_ctx,
                            desc_pool,
                        )?;
                    }
                    Token::EventQueue => {
                        let _ = self.event_evt.read();
                    }
                    Token::EventFd { id } => {
                        desc_pool = self.handle_event_fd(
                            &mut cmd_queue,
                            &mut event_queue,
                            &mut device,
                            desc_pool,
                            id,
                        )?;
                    }
                    Token::InterruptResample => {
                        self.interrupt.interrupt_resample();
                    }
                    Token::Kill => return Ok(()),
                }
            }
        }
    }
}
<commit_msg>devices: virtio: video: Pass DescPool by reference<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Worker that runs in a virtio-video thread.

use std::collections::{BTreeMap, VecDeque};

use sys_util::{error, EventFd, PollContext};
use vm_memory::GuestMemory;

use crate::virtio::queue::{DescriptorChain, Queue};
use crate::virtio::resource_bridge::ResourceRequestSocket;
use crate::virtio::video::command::{QueueType, VideoCmd};
use crate::virtio::video::device::{
    AsyncCmdTag, Device, Token, VideoCmdResponseType, VideoEvtResponseType,
};
use crate::virtio::video::error::{VideoError, VideoResult};
use crate::virtio::video::event::{self, EvtType, VideoEvt};
use crate::virtio::video::protocol;
use crate::virtio::video::response::{self, CmdResponse, Response};
use crate::virtio::video::{Error, Result};
use crate::virtio::{Interrupt, Reader, Writer};

pub struct Worker {
    pub interrupt: Interrupt,
    pub mem: GuestMemory,
    pub cmd_evt: EventFd,
    pub event_evt: EventFd,
    pub kill_evt: EventFd,
    pub resource_bridge: ResourceRequestSocket,
}

/// BTreeMap which stores descriptor chains in which asynchronous responses will be written.
type DescPool<'a> = BTreeMap<AsyncCmdTag, DescriptorChain<'a>>;
/// Pair of a descriptor chain and a response to be written.
type WritableResp<'a> = (DescriptorChain<'a>, VideoResult<response::CmdResponse>);

/// Invalidates and removes all pending asynchronous commands in a given `DescPool` value
/// and returns a list of `WritableResp` to be sent to the guest.
fn cancel_pending_requests<'a>(
    target_stream_id: u32,
    desc_pool: &mut DescPool<'a>,
) -> Vec<WritableResp<'a>> {
    let old_desc_pool = std::mem::take(desc_pool);
    let mut resps = vec![];
    for (key, value) in old_desc_pool.into_iter() {
        match key {
            AsyncCmdTag::Queue { stream_id, .. } if stream_id == target_stream_id => {
                resps.push((
                    value,
                    Ok(CmdResponse::ResourceQueue {
                        timestamp: 0,
                        flags: protocol::VIRTIO_VIDEO_BUFFER_FLAG_ERR,
                        size: 0,
                    }),
                ));
            }
            AsyncCmdTag::Drain { stream_id } | AsyncCmdTag::Clear { stream_id, .. }
                if stream_id == target_stream_id =>
            {
                // TODO(b/1518105): Use more appropriate error code if a new protocol supports one.
                resps.push((value, Err(VideoError::InvalidOperation)));
            }
            AsyncCmdTag::Queue { .. } | AsyncCmdTag::Drain { .. } | AsyncCmdTag::Clear { .. } => {
                // Keep commands for other streams.
                desc_pool.insert(key, value);
            }
        }
    }
    resps
}

impl Worker {
    /// Writes responses into the command queue.
    fn write_responses<'a>(
        &self,
        cmd_queue: &mut Queue,
        responses: &mut VecDeque<WritableResp>,
    ) -> Result<()> {
        let mut needs_interrupt_commandq = false;
        // Write responses into command virtqueue.
        while let Some((desc, resp)) = responses.pop_front() {
            let desc_index = desc.index;
            let mut writer = Writer::new(&self.mem, desc).map_err(Error::InvalidDescriptorChain)?;
            match resp {
                Ok(r) => {
                    if let Err(e) = r.write(&mut writer) {
                        error!("failed to write an OK response for {:?}: {}", r, e);
                    }
                }
                Err(err) => {
                    if let Err(e) = err.write(&mut writer) {
                        error!("failed to write an Error response for {:?}: {}", err, e);
                    }
                }
            }

            cmd_queue.add_used(&self.mem, desc_index, writer.bytes_written() as u32);
            needs_interrupt_commandq = true;
        }
        if needs_interrupt_commandq {
            self.interrupt.signal_used_queue(cmd_queue.vector);
        }
        Ok(())
    }

    /// Writes a `VideoEvt` into the event queue.
    fn write_event(&self, event_queue: &mut Queue, event: &mut event::VideoEvt) -> Result<()> {
        let desc = event_queue
            .peek(&self.mem)
            .ok_or_else(|| Error::DescriptorNotAvailable)?;
        event_queue.pop_peeked(&self.mem);

        let desc_index = desc.index;
        let mut writer = Writer::new(&self.mem, desc).map_err(Error::InvalidDescriptorChain)?;
        event
            .write(&mut writer)
            .map_err(|error| Error::WriteEventFailure {
                event: event.clone(),
                error,
            })?;
        event_queue.add_used(&self.mem, desc_index, writer.bytes_written() as u32);
        self.interrupt.signal_used_queue(event_queue.vector);
        Ok(())
    }

    /// Handles a `DescriptorChain` value sent via the command queue and returns a `VecDeque`
    /// of `WritableResp` to be sent to the guest.
    fn handle_command_desc<'a, T: Device>(
        &'a self,
        device: &mut T,
        poll_ctx: &PollContext<Token>,
        desc_pool: &mut DescPool<'a>,
        desc: DescriptorChain<'a>,
    ) -> Result<VecDeque<WritableResp<'a>>> {
        let mut resps: VecDeque<WritableResp> = Default::default();
        let mut reader =
            Reader::new(&self.mem, desc.clone()).map_err(Error::InvalidDescriptorChain)?;

        let cmd = VideoCmd::from_reader(&mut reader).map_err(Error::ReadFailure)?;

        // If a destruction command comes, cancel pending requests.
        match cmd {
            VideoCmd::ResourceDestroyAll { stream_id } | VideoCmd::StreamDestroy { stream_id } => {
                let rs = cancel_pending_requests(stream_id, desc_pool);
                resps.append(&mut Into::<VecDeque<_>>::into(rs));
            }
            _ => (),
        };

        // Process the command by the device.
        let resp = device.process_cmd(cmd, &poll_ctx, &self.resource_bridge);

        match resp {
            Ok(VideoCmdResponseType::Sync(r)) => {
                resps.push_back((desc.clone(), Ok(r)));
            }
            Ok(VideoCmdResponseType::Async(tag)) => {
                // If the command expects an asynchronous response,
                // store `desc` to use it after the back-end device notifies the
                // completion.
                desc_pool.insert(tag, desc);
            }
            Err(e) => {
                resps.push_back((desc.clone(), Err(e)));
            }
        }

        Ok(resps)
    }

    /// Handles each command in the command queue.
    fn handle_command_queue<'a, T: Device>(
        &'a self,
        cmd_queue: &mut Queue,
        device: &mut T,
        poll_ctx: &PollContext<Token>,
        desc_pool: &mut DescPool<'a>,
    ) -> Result<()> {
        let _ = self.cmd_evt.read();

        while let Some(desc) = cmd_queue.pop(&self.mem) {
            let mut resps = self.handle_command_desc(device, poll_ctx, desc_pool, desc)?;
            self.write_responses(cmd_queue, &mut resps)?;
        }
        Ok(())
    }

    /// Handles a `VideoEvtResponseType` value and returns a `VecDeque` of `WritableResp`
    /// to be sent to the guest.
    fn handle_event_resp<'a, T: Device>(
        &'a self,
        event_queue: &mut Queue,
        device: &mut T,
        desc_pool: &mut DescPool<'a>,
        resp: VideoEvtResponseType,
    ) -> Result<VecDeque<WritableResp>> {
        let mut responses: VecDeque<WritableResp> = Default::default();
        match resp {
            VideoEvtResponseType::AsyncCmd {
                tag: AsyncCmdTag::Drain { stream_id },
                resp,
            } => {
                let tag = AsyncCmdTag::Drain { stream_id };
                let drain_desc = desc_pool
                    .remove(&tag)
                    .ok_or_else(|| Error::UnexpectedResponse(tag))?;

                // When `Drain` request is completed, returns an empty output resource
                // with EOS flag first.
                let resource_id = device
                    .take_resource_id_to_notify_eos(stream_id)
                    .ok_or_else(|| Error::NoEOSBuffer { stream_id })?;

                let q_desc = desc_pool
                    .remove(&AsyncCmdTag::Queue {
                        stream_id,
                        queue_type: QueueType::Output,
                        resource_id,
                    })
                    .ok_or_else(|| Error::InvalidEOSResource {
                        stream_id,
                        resource_id,
                    })?;

                responses.push_back((
                    q_desc,
                    Ok(CmdResponse::ResourceQueue {
                        timestamp: 0,
                        flags: protocol::VIRTIO_VIDEO_BUFFER_FLAG_EOS,
                        size: 0,
                    }),
                ));

                // Then, responds the Drain request.
                responses.push_back((drain_desc, resp));
            }
            VideoEvtResponseType::AsyncCmd {
                tag:
                    AsyncCmdTag::Clear {
                        queue_type,
                        stream_id,
                    },
                resp,
            } => {
                let tag = AsyncCmdTag::Clear {
                    queue_type,
                    stream_id,
                };
                let desc = desc_pool
                    .remove(&tag)
                    .ok_or_else(|| Error::UnexpectedResponse(tag))?;

                // When `Clear` request is completed, invalidate all pending requests.
                let resps = cancel_pending_requests(stream_id, desc_pool);
                responses.append(&mut Into::<VecDeque<_>>::into(resps));

                // Then, responds the `Clear` request.
                responses.push_back((desc, resp));
            }
            VideoEvtResponseType::AsyncCmd { tag, resp } => {
                let desc = desc_pool
                    .remove(&tag)
                    .ok_or_else(|| Error::UnexpectedResponse(tag))?;
                responses.push_back((desc, resp));
            }
            VideoEvtResponseType::Event(mut evt) => {
                self.write_event(event_queue, &mut evt)?;
            }
        };
        Ok(responses)
    }

    /// Handles an event notified via an event FD.
    fn handle_event_fd<'a, T: Device>(
        &'a self,
        cmd_queue: &mut Queue,
        event_queue: &mut Queue,
        device: &mut T,
        desc_pool: &mut DescPool<'a>,
        stream_id: u32,
    ) -> Result<()> {
        let resp = device.process_event_fd(stream_id);
        match resp {
            Some(r) => match self.handle_event_resp(event_queue, device, desc_pool, r) {
                Ok(mut resps) => {
                    self.write_responses(cmd_queue, &mut resps)?;
                    Ok(())
                }
                Err(e) => {
                    // Ignore result of write_event for a fatal error.
                    let _ = self.write_event(
                        event_queue,
                        &mut VideoEvt {
                            typ: EvtType::Error,
                            stream_id,
                        },
                    );
                    Err(e)
                }
            },
            None => Ok(()),
        }
    }

    pub fn run<T: Device>(
        &mut self,
        mut cmd_queue: Queue,
        mut event_queue: Queue,
        mut device: T,
    ) -> Result<()> {
        let poll_ctx: PollContext<Token> = PollContext::build_with(&[
            (&self.cmd_evt, Token::CmdQueue),
            (&self.event_evt, Token::EventQueue),
            (&self.kill_evt, Token::Kill),
            (self.interrupt.get_resample_evt(), Token::InterruptResample),
        ])
        .map_err(Error::PollContextCreationFailed)?;

        // Stores descriptors in which responses for asynchronous commands will be written.
        let mut desc_pool: DescPool<'_> = Default::default();

        loop {
            let poll_events = poll_ctx.wait().map_err(Error::PollError)?;

            for poll_event in poll_events.iter_readable() {
                match poll_event.token() {
                    Token::CmdQueue => {
                        self.handle_command_queue(
                            &mut cmd_queue,
                            &mut device,
                            &poll_ctx,
                            &mut desc_pool,
                        )?;
                    }
                    Token::EventQueue => {
                        let _ = self.event_evt.read();
                    }
                    Token::EventFd { id } => {
                        self.handle_event_fd(
                            &mut cmd_queue,
                            &mut event_queue,
                            &mut device,
                            &mut desc_pool,
                            id,
                        )?;
                    }
                    Token::InterruptResample => {
                        self.interrupt.interrupt_resample();
                    }
                    Token::Kill => return Ok(()),
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use time;
use std::io::timer::sleep;

use GameWindow;
use keyboard;
use mouse;
use event;

use std::cmp;

/// Render argument.
#[deriving(Clone)]
pub struct RenderArgs {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// The width of rendered area.
    pub width: u32,
    /// The height of rendered area.
    pub height: u32,
}

/// Update argument.
#[deriving(Clone)]
pub struct UpdateArgs {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Key press arguments.
#[deriving(Clone)]
pub struct KeyPressArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Key release arguments.
#[deriving(Clone)]
pub struct KeyReleaseArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Mouse press arguments.
#[deriving(Clone)]
pub struct MousePressArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse release arguments.
#[deriving(Clone)]
pub struct MouseReleaseArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse move arguments.
#[deriving(Clone)]
pub struct MouseMoveArgs {
    /// x.
    pub x: f64,
    /// y.
    pub y: f64,
}

/// Mouse relative move arguments.
#[deriving(Clone)]
pub struct MouseRelativeMoveArgs {
    /// Delta x.
    pub dx: f64,
    /// Delta y.
    pub dy: f64,
}

/// Mouse scroll arguments.
#[deriving(Clone)]
pub struct MouseScrollArgs {
    /// x.
    pub x: f64,
    /// y.
    pub y: f64,
}

/// Contains the different game events.
#[deriving(Clone)]
pub enum GameEvent {
    /// Render graphics.
    Render(RenderArgs),
    /// Update physical state of the game.
    Update(UpdateArgs),
    /// Pressed a keyboard key.
    KeyPress(KeyPressArgs),
    /// Released a keyboard key.
    KeyRelease(KeyReleaseArgs),
    /// Pressed a mouse button.
    MousePress(MousePressArgs),
    /// Released a mouse button.
    MouseRelease(MouseReleaseArgs),
    /// Moved mouse cursor.
    MouseMove(MouseMoveArgs),
    /// Moved mouse relative, not bounded by cursor.
    MouseRelativeMove(MouseRelativeMoveArgs),
    /// Scrolled mouse.
    MouseScroll(MouseScrollArgs)
}

#[deriving(Show)]
enum GameIteratorState {
    RenderState,
    SwapBuffersState,
    UpdateLoopState,
    HandleEventsState,
    MouseRelativeMoveState(f64, f64),
    UpdateState,
}

/// Settings for the game loop behavior.
#[deriving(Clone)]
pub struct GameIteratorSettings {
    /// The number of updates per second (UPS).
    pub updates_per_second: u64,
    /// The maximum number of frames per second (FPS target).
    pub max_frames_per_second: u64,
}

/// A game loop iterator.
///
/// Example:
///
/// ```Rust
/// let game_iter_settings = GameIteratorSettings {
///     updates_per_second: 120,
///     max_frames_per_second: 60,
/// };
/// let mut game_iter = GameIterator::new(&mut window, &game_iter_settings);
/// loop {
///     match game_iter.next() {
///         None => break,
///         Some(mut e) => match e {
///             Render(ref mut args) => {
///                 // Create graphics context with absolute coordinates.
///                 let c = Context::abs(args.width as f64, args.height as f64);
///                 // Do rendering here.
///             },
///             _ => {},
///         },
///     }
/// }
/// ```
pub struct GameIterator<'a, W> {
    /// The game window used by iterator.
    pub game_window: &'a mut W,
    state: GameIteratorState,
    last_update: u64,
    last_frame: u64,
    dt_update_in_ns: u64,
    dt_frame_in_ns: u64,
    dt: f64,
}

static billion: u64 = 1_000_000_000;

impl<'a, W: GameWindow> GameIterator<'a, W> {
    /// Creates a new game iterator.
    pub fn new(
        game_window: &'a mut W,
        settings: &GameIteratorSettings
    ) -> GameIterator<'a, W> {
        let updates_per_second: u64 = settings.updates_per_second;
        let max_frames_per_second: u64 = settings.max_frames_per_second;

        let start = time::precise_time_ns();
        GameIterator {
            game_window: game_window,
            state: RenderState,
            last_update: start,
            last_frame: start,
            dt_update_in_ns: billion / updates_per_second,
            dt_frame_in_ns: billion / max_frames_per_second,
            dt: 1.0 / updates_per_second as f64,
        }
    }
}

impl<'a, W: GameWindow>
Iterator<GameEvent>
for GameIterator<'a, W> {
    /// Returns the next game event.
    fn next(&mut self) -> Option<GameEvent> {
        loop {
            match self.state {
                RenderState => {
                    if self.game_window.should_close() { return None; }

                    let start_render = time::precise_time_ns();
                    let jump_frames = cmp::max(1, (start_render - self.last_frame) / self.dt_frame_in_ns);
                    self.last_frame += self.dt_frame_in_ns * jump_frames;

                    let (w, h) = self.game_window.get_size();
                    if w != 0 && h != 0 {
                        // Swap buffers next time.
                        self.state = SwapBuffersState;
                        return Some(Render(RenderArgs {
                                // Extrapolate time forward to allow smooth motion.
                                ext_dt: (start_render - self.last_update) as f64 / billion as f64,
                                width: w,
                                height: h,
                            }
                        ));
                    }

                    self.state = UpdateLoopState;
                },
                SwapBuffersState => {
                    self.game_window.swap_buffers();
                    self.state = UpdateLoopState;
                },
                UpdateLoopState => {
                    let current_time = time::precise_time_ns();
                    let next_frame = self.last_frame + self.dt_frame_in_ns;
                    let next_update = self.last_update + self.dt_update_in_ns;
                    let next_event = cmp::min(next_frame, next_update);
                    if next_event > current_time {
                        sleep( (next_event - current_time) / 1_000_000 );
                    } else if next_event == next_frame {
                        self.state = RenderState;
                    } else {
                        self.state = HandleEventsState;
                    }
                },
                HandleEventsState => {
                    // Handle all events before updating.
                    return match self.game_window.poll_event() {
                        event::KeyPressed(key) => {
                            Some(KeyPress(KeyPressArgs {
                                key: key,
                            }))
                        },
                        event::KeyReleased(key) => {
                            Some(KeyRelease(KeyReleaseArgs {
                                key: key,
                            }))
                        },
                        event::MouseButtonPressed(mouse_button) => {
                            Some(MousePress(MousePressArgs {
                                button: mouse_button,
                            }))
                        },
                        event::MouseButtonReleased(mouse_button) => {
                            Some(MouseRelease(MouseReleaseArgs {
                                button: mouse_button,
                            }))
                        },
                        event::MouseMoved(x, y, relative_move) => {
                            match relative_move {
                                Some((dx, dy)) =>
                                    self.state = MouseRelativeMoveState(dx, dy),
                                None => {},
                            };
                            Some(MouseMove(MouseMoveArgs {
                                x: x,
                                y: y,
                            }))
                        },
                        event::MouseScrolled(x, y) => {
                            Some(MouseScroll(MouseScrollArgs {
                                x: x,
                                y: y
                            }))
                        },
                        event::NoEvent => {
                            self.state = UpdateState;
                            continue;
                        },
                    }
                },
                MouseRelativeMoveState(dx, dy) => {
                    self.state = HandleEventsState;
                    return Some(MouseRelativeMove(MouseRelativeMoveArgs {
                        dx: dx,
                        dy: dy,
                    }));
                },
                UpdateState => {
                    self.state = UpdateLoopState;
                    self.last_update += self.dt_update_in_ns;
                    return Some(Update(UpdateArgs{
                        dt: self.dt,
                    }));
                },
            };
        }
    }
}
<commit_msg>Updated doc examplee for `GameIterator`<commit_after>use time;
use std::io::timer::sleep;

use GameWindow;
use keyboard;
use mouse;
use event;

use std::cmp;

/// Render argument.
#[deriving(Clone)]
pub struct RenderArgs {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// The width of rendered area.
    pub width: u32,
    /// The height of rendered area.
    pub height: u32,
}

/// Update argument.
#[deriving(Clone)]
pub struct UpdateArgs {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Key press arguments.
#[deriving(Clone)]
pub struct KeyPressArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Key release arguments.
#[deriving(Clone)]
pub struct KeyReleaseArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Mouse press arguments.
#[deriving(Clone)]
pub struct MousePressArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse release arguments.
#[deriving(Clone)]
pub struct MouseReleaseArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse move arguments.
#[deriving(Clone)]
pub struct MouseMoveArgs {
    /// x.
    pub x: f64,
    /// y.
    pub y: f64,
}

/// Mouse relative move arguments.
#[deriving(Clone)]
pub struct MouseRelativeMoveArgs {
    /// Delta x.
    pub dx: f64,
    /// Delta y.
    pub dy: f64,
}

/// Mouse scroll arguments.
#[deriving(Clone)]
pub struct MouseScrollArgs {
    /// x.
    pub x: f64,
    /// y.
    pub y: f64,
}

/// Contains the different game events.
#[deriving(Clone)]
pub enum GameEvent {
    /// Render graphics.
    Render(RenderArgs),
    /// Update physical state of the game.
    Update(UpdateArgs),
    /// Pressed a keyboard key.
    KeyPress(KeyPressArgs),
    /// Released a keyboard key.
    KeyRelease(KeyReleaseArgs),
    /// Pressed a mouse button.
    MousePress(MousePressArgs),
    /// Released a mouse button.
    MouseRelease(MouseReleaseArgs),
    /// Moved mouse cursor.
    MouseMove(MouseMoveArgs),
    /// Moved mouse relative, not bounded by cursor.
    MouseRelativeMove(MouseRelativeMoveArgs),
    /// Scrolled mouse.
    MouseScroll(MouseScrollArgs)
}

#[deriving(Show)]
enum GameIteratorState {
    RenderState,
    SwapBuffersState,
    UpdateLoopState,
    HandleEventsState,
    MouseRelativeMoveState(f64, f64),
    UpdateState,
}

/// Settings for the game loop behavior.
#[deriving(Clone)]
pub struct GameIteratorSettings {
    /// The number of updates per second (UPS).
    pub updates_per_second: u64,
    /// The maximum number of frames per second (FPS target).
    pub max_frames_per_second: u64,
}

/// A game loop iterator.
///
/// Example:
///
/// ```Rust
/// let game_iter_settings = GameIteratorSettings {
///     updates_per_second: 120,
///     max_frames_per_second: 60,
/// };
/// let ref mut gl = Gl::new();
/// for e in GameIterator::new(&mut window, &game_iter_settings) {
///     match e {
///         Render(args) => {
///             // Set the viewport in window to render graphics.
///             gl.viewport(0, 0, args.width as i32, args.height as i32);
///             // Create graphics context with absolute coordinates.
///             let c = Context::abs(args.width as f64, args.height as f64);
///             // Do rendering here.
///         },
///     }
/// }
/// ```
pub struct GameIterator<'a, W> {
    /// The game window used by iterator.
    pub game_window: &'a mut W,
    state: GameIteratorState,
    last_update: u64,
    last_frame: u64,
    dt_update_in_ns: u64,
    dt_frame_in_ns: u64,
    dt: f64,
}

static billion: u64 = 1_000_000_000;

impl<'a, W: GameWindow> GameIterator<'a, W> {
    /// Creates a new game iterator.
    pub fn new(
        game_window: &'a mut W,
        settings: &GameIteratorSettings
    ) -> GameIterator<'a, W> {
        let updates_per_second: u64 = settings.updates_per_second;
        let max_frames_per_second: u64 = settings.max_frames_per_second;

        let start = time::precise_time_ns();
        GameIterator {
            game_window: game_window,
            state: RenderState,
            last_update: start,
            last_frame: start,
            dt_update_in_ns: billion / updates_per_second,
            dt_frame_in_ns: billion / max_frames_per_second,
            dt: 1.0 / updates_per_second as f64,
        }
    }
}

impl<'a, W: GameWindow>
Iterator<GameEvent>
for GameIterator<'a, W> {
    /// Returns the next game event.
    fn next(&mut self) -> Option<GameEvent> {
        loop {
            match self.state {
                RenderState => {
                    if self.game_window.should_close() { return None; }

                    let start_render = time::precise_time_ns();
                    let jump_frames = cmp::max(1, (start_render - self.last_frame) / self.dt_frame_in_ns);
                    self.last_frame += self.dt_frame_in_ns * jump_frames;

                    let (w, h) = self.game_window.get_size();
                    if w != 0 && h != 0 {
                        // Swap buffers next time.
                        self.state = SwapBuffersState;
                        return Some(Render(RenderArgs {
                                // Extrapolate time forward to allow smooth motion.
                                ext_dt: (start_render - self.last_update) as f64 / billion as f64,
                                width: w,
                                height: h,
                            }
                        ));
                    }

                    self.state = UpdateLoopState;
                },
                SwapBuffersState => {
                    self.game_window.swap_buffers();
                    self.state = UpdateLoopState;
                },
                UpdateLoopState => {
                    let current_time = time::precise_time_ns();
                    let next_frame = self.last_frame + self.dt_frame_in_ns;
                    let next_update = self.last_update + self.dt_update_in_ns;
                    let next_event = cmp::min(next_frame, next_update);
                    if next_event > current_time {
                        sleep( (next_event - current_time) / 1_000_000 );
                    } else if next_event == next_frame {
                        self.state = RenderState;
                    } else {
                        self.state = HandleEventsState;
                    }
                },
                HandleEventsState => {
                    // Handle all events before updating.
                    return match self.game_window.poll_event() {
                        event::KeyPressed(key) => {
                            Some(KeyPress(KeyPressArgs {
                                key: key,
                            }))
                        },
                        event::KeyReleased(key) => {
                            Some(KeyRelease(KeyReleaseArgs {
                                key: key,
                            }))
                        },
                        event::MouseButtonPressed(mouse_button) => {
                            Some(MousePress(MousePressArgs {
                                button: mouse_button,
                            }))
                        },
                        event::MouseButtonReleased(mouse_button) => {
                            Some(MouseRelease(MouseReleaseArgs {
                                button: mouse_button,
                            }))
                        },
                        event::MouseMoved(x, y, relative_move) => {
                            match relative_move {
                                Some((dx, dy)) =>
                                    self.state = MouseRelativeMoveState(dx, dy),
                                None => {},
                            };
                            Some(MouseMove(MouseMoveArgs {
                                x: x,
                                y: y,
                            }))
                        },
                        event::MouseScrolled(x, y) => {
                            Some(MouseScroll(MouseScrollArgs {
                                x: x,
                                y: y
                            }))
                        },
                        event::NoEvent => {
                            self.state = UpdateState;
                            continue;
                        },
                    }
                },
                MouseRelativeMoveState(dx, dy) => {
                    self.state = HandleEventsState;
                    return Some(MouseRelativeMove(MouseRelativeMoveArgs {
                        dx: dx,
                        dy: dy,
                    }));
                },
                UpdateState => {
                    self.state = UpdateLoopState;
                    self.last_update += self.dt_update_in_ns;
                    return Some(Update(UpdateArgs{
                        dt: self.dt,
                    }));
                },
            };
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Algebra Developers.
//
// 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::ops::{Add, Mul};

use general::{Op, Additive, Multiplicative};

/// Types that are closed under a given operator.
///
/// ~~~notrust
/// a, b ∈ Self ⇒ a ∘ b ∈ Self
/// ~~~
pub trait Magma<O: Op>
    : Sized + Clone
{
    /// Performs an operation.
    fn operate(self, Self) -> Self;
    /// Performs specific operation.
    #[inline]
    fn op(self, _: O, lhs: Self) -> Self {
        self.operate(lhs)
    }
}

impl<T> Magma<Additive> for T
where T: Add<T, Output = T> + Clone,
{
    #[inline]
    fn operate(self, lhs: Self) -> Self {
        self + lhs
    }
}

impl<T> Magma<Multiplicative> for T
where T: Mul<T, Output = T> + Clone,
{
    #[inline]
    fn operate(self, lhs: Self) -> Self {
        self * lhs
    }
}
<commit_msg>Remove auto-impls. for Magma.<commit_after>// Copyright 2013-2014 The Algebra Developers.
//
// 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::ops::{Add, Mul};

use general::{Op, Additive, Multiplicative};

/// Types that are closed under a given operator.
///
/// ~~~notrust
/// a, b ∈ Self ⇒ a ∘ b ∈ Self
/// ~~~
pub trait Magma<O: Op>
    : Sized + Clone
{
    /// Performs an operation.
    fn operate(self, Self) -> Self;
    /// Performs specific operation.
    #[inline]
    fn op(self, _: O, lhs: Self) -> Self {
        self.operate(lhs)
    }
}

macro_rules! impl_magma(
    ($M:ty; $op: ident; $($T:ty),* $(,)*) => {
        $(impl Magma<$M> for $T {
            #[inline]
            fn operate(self, lhs: Self) -> Self {
                self.$op(lhs)
            }
        })*
    }
);

impl_magma!(Additive; add; u8, u16, u32, u64, i8, i16, i32, i64, f32, f64);
impl_magma!(Multiplicative; mul; u8, u16, u32, u64, i8, i16, i32, i64, f32, f64);
<|endoftext|>