<commit_before>use screen::*;
use context::{Context, GameState};
use ui::{create_ui, Ui};
use piston_window::{self, PistonWindow};
use conrod::{Canvas, Button, Widget, Positionable, Sizeable, Labelable};
use conrod::color::{self, Colorable};

pub struct MainMenu {
    ui: Ui,
    state: Option<State>,
    new_game: bool,
}

impl MainMenu {
    pub fn new(window: &PistonWindow, context: &mut Context) -> Self {
        MainMenu {
            ui: create_ui(&window, &context.assets_path),
            state: None,
            new_game: context.game_state == GameState::NotStarted,
        }
    }
}

enum State {
    NewGame,
    Options,
    Exit,
}

impl Screen for MainMenu {
    fn on_input(&mut self, _: &piston_window::Input, window: &PistonWindow, context: &mut Context) -> InputResults {
        self.ui.handle_event(window);
        let mut result = Vec::new();

        match self.state.take() {
            Some(State::NewGame) => {
                result.push(InputResult::PopScreen);

                if self.new_game {
                    // Start new game.
                    result.push(InputResult::PushScreen(Box::new(Battle::new(&window, context))));
                    context.game_state = GameState::InProgress;
                }
            }
            Some(State::Options) => {
                result.push(InputResult::PushScreen(Box::new(Options::new(&window, context))));
            }
            Some(State::Exit) => {
                result.push(InputResult::Exit);
            }
            None => {}
        }

        result
    }

    fn on_draw(&mut self, _: &piston_window::RenderArgs, window: &PistonWindow) {
        self.ui.handle_event(window);
        window.draw_2d(|context, graphics| self.ui.draw_if_changed(context, graphics));
    }

    fn on_update(&mut self, _: &piston_window::UpdateArgs) {
        let button_color = color::rgb(0.4, 0.75, 0.6);
        let game_button_text = if self.new_game {
            "New Game"
        }
        else {
            "Continue"
        };

        let state = &mut self.state;

        self.ui.set_widgets(|mut ui| {
            Canvas::new()
                .pad(30.)
                .color(color::rgb(0.2, 0.35, 0.45))
                .scroll_kids()
                .set(CANVAS, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .color(button_color)
                .label(game_button_text)
                .react(|| *state = Some(State::NewGame))
                .set(NEW_OR_CONTINUE_GAME_BUTTON, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .down_from(NEW_OR_CONTINUE_GAME_BUTTON, 45.0)
                .color(button_color)
                .label("Options")
                .react(|| *state = Some(State::Options))
                .set(OPTIONS_BUTTON, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .down_from(OPTIONS_BUTTON, 45.0)
                .color(button_color)
                .label("Exit")
                .react(|| *state = Some(State::Exit))
                .set(EXIT_BUTTON, &mut ui);
        });
    }
}

widget_ids! {
    CANVAS,
    NEW_OR_CONTINUE_GAME_BUTTON,
    OPTIONS_BUTTON,
    EXIT_BUTTON,
}
<commit_msg>Format<commit_after>use screen::*;
use context::{Context, GameState};
use ui::{create_ui, Ui};
use piston_window::{self, PistonWindow};
use conrod::{Canvas, Button, Widget, Positionable, Sizeable, Labelable};
use conrod::color::{self, Colorable};

pub struct MainMenu {
    ui: Ui,
    state: Option<State>,
    new_game: bool,
}

impl MainMenu {
    pub fn new(window: &PistonWindow, context: &mut Context) -> Self {
        MainMenu {
            ui: create_ui(&window, &context.assets_path),
            state: None,
            new_game: context.game_state == GameState::NotStarted,
        }
    }
}

enum State {
    NewGame,
    Options,
    Exit,
}

impl Screen for MainMenu {
    fn on_input(&mut self, _: &piston_window::Input, window: &PistonWindow, context: &mut Context) -> InputResults {
        self.ui.handle_event(window);
        let mut result = Vec::new();

        match self.state.take() {
            Some(State::NewGame) => {
                result.push(InputResult::PopScreen);

                if self.new_game {
                    // Start new game.
                    result.push(InputResult::PushScreen(Box::new(Battle::new(&window, context))));
                    context.game_state = GameState::InProgress;
                }
            }
            Some(State::Options) => {
                result.push(InputResult::PushScreen(Box::new(Options::new(&window, context))));
            }
            Some(State::Exit) => {
                result.push(InputResult::Exit);
            }
            None => {}
        }

        result
    }

    fn on_draw(&mut self, _: &piston_window::RenderArgs, window: &PistonWindow) {
        self.ui.handle_event(window);
        window.draw_2d(|context, graphics| self.ui.draw_if_changed(context, graphics));
    }

    fn on_update(&mut self, _: &piston_window::UpdateArgs) {
        let button_color = color::rgb(0.4, 0.75, 0.6);
        let game_button_text = if self.new_game {
            "New Game"
        } else {
            "Continue"
        };

        let state = &mut self.state;

        self.ui.set_widgets(|mut ui| {
            Canvas::new()
                .pad(30.)
                .color(color::rgb(0.2, 0.35, 0.45))
                .scroll_kids()
                .set(CANVAS, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .color(button_color)
                .label(game_button_text)
                .react(|| *state = Some(State::NewGame))
                .set(NEW_OR_CONTINUE_GAME_BUTTON, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .down_from(NEW_OR_CONTINUE_GAME_BUTTON, 45.0)
                .color(button_color)
                .label("Options")
                .react(|| *state = Some(State::Options))
                .set(OPTIONS_BUTTON, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .down_from(OPTIONS_BUTTON, 45.0)
                .color(button_color)
                .label("Exit")
                .react(|| *state = Some(State::Exit))
                .set(EXIT_BUTTON, &mut ui);
        });
    }
}

widget_ids! {
    CANVAS,
    NEW_OR_CONTINUE_GAME_BUTTON,
    OPTIONS_BUTTON,
    EXIT_BUTTON,
}
<|endoftext|>


<commit_before>//! Implements iterative deepening, aspiration windows, multi-PV.
//!
//! Iterative deepening works as follows: the program starts with a
//! one ply search, then increments the search depth and does another
//! search. This process is repeated until the time allocated for the
//! search is exhausted. In case of an unfinished search, the program
//! always has the option to fall back to the move selected in the
//! last iteration of the search.
//!
//! Aspiration windows are a way to reduce the search space in the
//! search. The way it works is that we get the value from the last
//! search iteration, calculate a window around it, and use this as
//! alpha-beta bounds for the next search. Because the window is
//! narrower, more beta cutoffs are achieved, and the search takes a
//! shorter time. The drawback is that if the true score is outside
//! this window, then a costly re-search must be made. But then most
//! probably the re-search will be much faster, because many positions
//! will be remembered from the transposition table.
//!
//! In multi-PV mode the engine calculates and sends to the GUI
//! several principal variations (PV), each one starting with a
//! different first move.

use std::cmp::{min, max};
use std::mem;
use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
use basetypes::*;
use moves::*;
use tt::*;
use position::Position;
use search::MAX_DEPTH;
use search::threading::{Command, Report, serve_simple, serve_deepening};

/// The half-width of the initial aspiration window.
const INITIAL_ASPIRATION_HALFWIDTH: Value = 17; // 16;

/// The `SearchExecutor` trait is used to execute consecutive searches
/// in different starting positions.
pub trait SearchExecutor {
    /// Creates a new instance.
    fn new(tt: Arc<Tt>) -> Self;

    /// Starts a new search.
    ///
    /// * `search_id`: a number identifying the new search;
    ///
    /// * `position`: the root position;
    ///
    /// * `depth`: the requested search depth;
    ///
    /// * `lower_bound`: the lower bound for the new search;
    ///
    /// * `upper_bound`: the upper bound for the new search;
    ///
    /// * `value`: the evaluation of the root position so far, or
    ///   `VALUE_UNKNOWN` if not available.
    ///
    /// * `searchmoves`: restricts the analysis to the supplied list
    ///   of moves only (no restrictions if the suppied list is
    ///   empty);
    ///
    /// * `variation_count`: specifies how many best lines of play to
    ///   calculate (the first move in each line will be different).
    ///
    /// After calling `start_search`, `try_recv_report` must be called
    /// periodically until the returned report indicates that the
    /// search is done. A new search must not be started until the
    /// previous search is done.
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize);

    /// Attempts to return a search report without blocking.
    fn try_recv_report(&mut self) -> Result<Report, TryRecvError>;

    /// Requests the termination of the current search.
    ///
    /// After calling `terminate`, `try_recv_report` must continue to
    /// be called periodically until the returned report indicates
    /// that the search is done.
    fn terminate_search(&mut self);
}

/// Executes bare alpha-beta searches to a fixed depth.
pub struct SimpleSearcher {
    thread: Option<thread::JoinHandle<()>>,
    thread_commands: Sender<Command>,
    thread_reports: Receiver<Report>,
}

impl SearchExecutor for SimpleSearcher {
    fn new(tt: Arc<Tt>) -> SimpleSearcher {
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        SimpleSearcher {
            thread: Some(thread::spawn(move || {
                serve_simple(tt, commands_rx, reports_tx);
            })),
            thread_commands: commands_tx,
            thread_reports: reports_rx,
        }
    }

    #[allow(unused_variables)]
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);
        debug_assert!(searchmoves.is_empty());
        self.thread_commands
            .send(Command::Search {
                search_id: search_id,
                position: position,
                depth: depth,
                lower_bound: lower_bound,
                upper_bound: upper_bound,
            })
            .unwrap();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        self.thread_reports.try_recv()
    }

    fn terminate_search(&mut self) {
        self.thread_commands.send(Command::Stop).unwrap();
    }
}

impl Drop for SimpleSearcher {
    fn drop(&mut self) {
        self.thread_commands.send(Command::Exit).unwrap();
        self.thread.take().unwrap().join().unwrap();
    }
}

/// Executes multi-PV searches to a fixed depth.
pub struct MultipvSearcher;

/// Executes multi-PV searches to a fixed depth with aspiration.
pub struct AspirationSearcher {
    search_id: usize,
    position: Position,
    depth: u8,
    lower_bound: Value,
    upper_bound: Value,
    value: Value,
    searchmoves: Vec<Move>,
    variation_count: usize,

    /// `true` if the current search has been terminated.
    search_is_terminated: bool,

    /// The number of positions analyzed during previous (failed) searches.
    previously_searched_nodes: NodeCount,

    /// The aspiration window will be widened by this value if the
    /// search fails. (We use `isize` to avoid overflows.)
    delta: isize,

    /// The lower bound of the aspiration window.
    alpha: Value,

    /// The upper bound of the aspiration window.
    beta: Value,

    /// The real work will be handed over to `SimpleSearcher`.
    searcher: SimpleSearcher,
}

impl AspirationSearcher {
    /// A helper method. It tells `self.searcher` to run a new search.
    fn start_aspirated_search(&mut self) {
        self.searcher.start_search(0,
                                   self.position.clone(),
                                   self.depth,
                                   self.alpha,
                                   self.beta,
                                   self.value,
                                   self.searchmoves.clone(),
                                   self.variation_count);
    }

    /// A helper method. It multiplies `self.delta` by a constant.
    fn increase_delta(&mut self) {
        self.delta += 3 * self.delta / 8;
        if self.delta > 1500 {
            self.delta = 1_000_000;
        }
    }

    /// A helper method. It widens the aspiration window if necessary.
    fn widen_aspiration_window(&mut self) -> bool {
        let v = self.value as isize;
        if self.value <= self.alpha && self.lower_bound < self.alpha {
            // Set smaller `self.alpha`.
            self.alpha = max(v - self.delta, self.lower_bound as isize) as Value;
            self.increase_delta();
            return true;
        } else if self.value >= self.beta && self.upper_bound > self.beta {
            // Set bigger `self.beta`.
            self.beta = min(v + self.delta, self.upper_bound as isize) as Value;
            self.increase_delta();
            return true;
        }
        false
    }
}

impl SearchExecutor for AspirationSearcher {
    fn new(tt: Arc<Tt>) -> AspirationSearcher {
        let mut this: AspirationSearcher = unsafe { mem::uninitialized() };
        this.searcher = SimpleSearcher::new(tt);
        this
    }

    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);
        self.search_id = search_id;
        self.position = position;
        self.depth = depth;
        self.lower_bound = lower_bound;
        self.upper_bound = upper_bound;
        self.value = value;
        self.searchmoves = searchmoves;
        self.variation_count = variation_count;
        self.search_is_terminated = false;
        self.previously_searched_nodes = 0;
        self.delta = INITIAL_ASPIRATION_HALFWIDTH as isize;

        // Set the initial aspiration window (`self.alpha`, `self.beta`).
        let (a, b) = if value == VALUE_UNKNOWN || value < lower_bound || value > upper_bound {
            (lower_bound, upper_bound)
        } else {
            let v = value as isize;
            (max(v - self.delta, lower_bound as isize) as Value,
             min(v + self.delta, upper_bound as isize) as Value)
        };
        self.alpha = a;
        self.beta = b;

        self.start_aspirated_search();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        let Report { searched_nodes, depth, value, best_moves, done, .. } =
            try!(self.searcher.try_recv_report());
        let searched_nodes = self.previously_searched_nodes + searched_nodes;
        let depth = if done && !self.search_is_terminated {
            self.previously_searched_nodes = searched_nodes;
            self.value = value;
            if self.widen_aspiration_window() {
                // Start a re-search.
                self.start_aspirated_search();
                return Err(TryRecvError::Empty);
            }
            depth
        } else {
            0
        };

        return Ok(Report {
            search_id: self.search_id,
            searched_nodes: searched_nodes,
            depth: depth,
            value: self.value,
            best_moves: best_moves,
            done: done,
        });
    }

    fn terminate_search(&mut self) {
        self.search_is_terminated = true;
        self.searcher.terminate_search();
    }
}

/// Executes deepeing multi-PV searches with aspiration.
pub struct DeepeningSearcher {
    thread: Option<thread::JoinHandle<()>>,
    thread_commands: Sender<Command>,
    thread_reports: Receiver<Report>,
}

impl SearchExecutor for DeepeningSearcher {
    fn new(tt: Arc<Tt>) -> DeepeningSearcher {
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        DeepeningSearcher {
            thread: Some(thread::spawn(move || {
                serve_deepening(tt, commands_rx, reports_tx);
            })),
            thread_commands: commands_tx,
            thread_reports: reports_rx,
        }
    }

    #[allow(unused_variables)]
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);
        self.thread_commands
            .send(Command::Search {
                search_id: search_id,
                position: position,
                depth: depth,
                lower_bound: lower_bound,
                upper_bound: upper_bound,
            })
            .unwrap();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        self.thread_reports.try_recv()
    }

    fn terminate_search(&mut self) {
        self.thread_commands.send(Command::Stop).unwrap();
    }
}

impl Drop for DeepeningSearcher {
    fn drop(&mut self) {
        self.thread_commands.send(Command::Exit).unwrap();
        self.thread.take().unwrap().join().unwrap();
    }
}
<commit_msg>remove constant<commit_after>//! Implements iterative deepening, aspiration windows, multi-PV.
//!
//! Iterative deepening works as follows: the program starts with a
//! one ply search, then increments the search depth and does another
//! search. This process is repeated until the time allocated for the
//! search is exhausted. In case of an unfinished search, the program
//! always has the option to fall back to the move selected in the
//! last iteration of the search.
//!
//! Aspiration windows are a way to reduce the search space in the
//! search. The way it works is that we get the value from the last
//! search iteration, calculate a window around it, and use this as
//! alpha-beta bounds for the next search. Because the window is
//! narrower, more beta cutoffs are achieved, and the search takes a
//! shorter time. The drawback is that if the true score is outside
//! this window, then a costly re-search must be made. But then most
//! probably the re-search will be much faster, because many positions
//! will be remembered from the transposition table.
//!
//! In multi-PV mode the engine calculates and sends to the GUI
//! several principal variations (PV), each one starting with a
//! different first move.

use std::cmp::{min, max};
use std::mem;
use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
use basetypes::*;
use moves::*;
use tt::*;
use position::Position;
use search::MAX_DEPTH;
use search::threading::{Command, Report, serve_simple, serve_deepening};

/// The `SearchExecutor` trait is used to execute consecutive searches
/// in different starting positions.
pub trait SearchExecutor {
    /// Creates a new instance.
    fn new(tt: Arc<Tt>) -> Self;

    /// Starts a new search.
    ///
    /// * `search_id`: a number identifying the new search;
    ///
    /// * `position`: the root position;
    ///
    /// * `depth`: the requested search depth;
    ///
    /// * `lower_bound`: the lower bound for the new search;
    ///
    /// * `upper_bound`: the upper bound for the new search;
    ///
    /// * `value`: the evaluation of the root position so far, or
    ///   `VALUE_UNKNOWN` if not available.
    ///
    /// * `searchmoves`: restricts the analysis to the supplied list
    ///   of moves only (no restrictions if the suppied list is
    ///   empty);
    ///
    /// * `variation_count`: specifies how many best lines of play to
    ///   calculate (the first move in each line will be different).
    ///
    /// After calling `start_search`, `try_recv_report` must be called
    /// periodically until the returned report indicates that the
    /// search is done. A new search must not be started until the
    /// previous search is done.
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize);

    /// Attempts to return a search report without blocking.
    fn try_recv_report(&mut self) -> Result<Report, TryRecvError>;

    /// Requests the termination of the current search.
    ///
    /// After calling `terminate`, `try_recv_report` must continue to
    /// be called periodically until the returned report indicates
    /// that the search is done.
    fn terminate_search(&mut self);
}

/// Executes bare alpha-beta searches to a fixed depth.
pub struct SimpleSearcher {
    thread: Option<thread::JoinHandle<()>>,
    thread_commands: Sender<Command>,
    thread_reports: Receiver<Report>,
}

impl SearchExecutor for SimpleSearcher {
    fn new(tt: Arc<Tt>) -> SimpleSearcher {
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        SimpleSearcher {
            thread: Some(thread::spawn(move || {
                serve_simple(tt, commands_rx, reports_tx);
            })),
            thread_commands: commands_tx,
            thread_reports: reports_rx,
        }
    }

    #[allow(unused_variables)]
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);
        debug_assert!(searchmoves.is_empty());
        self.thread_commands
            .send(Command::Search {
                search_id: search_id,
                position: position,
                depth: depth,
                lower_bound: lower_bound,
                upper_bound: upper_bound,
            })
            .unwrap();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        self.thread_reports.try_recv()
    }

    fn terminate_search(&mut self) {
        self.thread_commands.send(Command::Stop).unwrap();
    }
}

impl Drop for SimpleSearcher {
    fn drop(&mut self) {
        self.thread_commands.send(Command::Exit).unwrap();
        self.thread.take().unwrap().join().unwrap();
    }
}

/// Executes multi-PV searches to a fixed depth.
pub struct MultipvSearcher;

/// Executes multi-PV searches to a fixed depth with aspiration.
pub struct AspirationSearcher {
    search_id: usize,
    position: Position,
    depth: u8,
    lower_bound: Value,
    upper_bound: Value,
    value: Value,
    searchmoves: Vec<Move>,
    variation_count: usize,

    /// `true` if the current search has been terminated.
    search_is_terminated: bool,

    /// The number of positions analyzed during previous (failed) searches.
    previously_searched_nodes: NodeCount,

    /// The aspiration window will be widened by this value if the
    /// search fails. (We use `isize` to avoid overflows.)
    delta: isize,

    /// The lower bound of the aspiration window.
    alpha: Value,

    /// The upper bound of the aspiration window.
    beta: Value,

    /// The real work will be handed over to `SimpleSearcher`.
    searcher: SimpleSearcher,
}

impl AspirationSearcher {
    /// A helper method. It tells `self.searcher` to run a new search.
    fn start_aspirated_search(&mut self) {
        self.searcher.start_search(0,
                                   self.position.clone(),
                                   self.depth,
                                   self.alpha,
                                   self.beta,
                                   self.value,
                                   self.searchmoves.clone(),
                                   self.variation_count);
    }

    /// A helper method. It multiplies `self.delta` by a constant.
    fn increase_delta(&mut self) {
        self.delta += 3 * self.delta / 8;
        if self.delta > 1500 {
            self.delta = 1_000_000;
        }
    }

    /// A helper method. It widens the aspiration window if necessary.
    fn widen_aspiration_window(&mut self) -> bool {
        let v = self.value as isize;
        if self.value <= self.alpha && self.lower_bound < self.alpha {
            // Set smaller `self.alpha`.
            self.alpha = max(v - self.delta, self.lower_bound as isize) as Value;
            self.increase_delta();
            return true;
        } else if self.value >= self.beta && self.upper_bound > self.beta {
            // Set bigger `self.beta`.
            self.beta = min(v + self.delta, self.upper_bound as isize) as Value;
            self.increase_delta();
            return true;
        }
        false
    }
}

impl SearchExecutor for AspirationSearcher {
    fn new(tt: Arc<Tt>) -> AspirationSearcher {
        let mut this: AspirationSearcher = unsafe { mem::uninitialized() };
        this.searcher = SimpleSearcher::new(tt);
        this
    }

    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);

        self.search_id = search_id;
        self.position = position;
        self.depth = depth;
        self.lower_bound = lower_bound;
        self.upper_bound = upper_bound;
        self.value = value;
        self.searchmoves = searchmoves;
        self.variation_count = variation_count;
        self.search_is_terminated = false;
        self.previously_searched_nodes = 0;

        // The half-width of the initial aspiration window.
        self.delta = 17; // TODO: make this `16`?

        // Set the initial aspiration window (`self.alpha`, `self.beta`).
        let (a, b) = if value == VALUE_UNKNOWN || value < lower_bound || value > upper_bound {
            (lower_bound, upper_bound)
        } else {
            let v = value as isize;
            (max(v - self.delta, lower_bound as isize) as Value,
             min(v + self.delta, upper_bound as isize) as Value)
        };
        self.alpha = a;
        self.beta = b;

        self.start_aspirated_search();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        let Report { searched_nodes, depth, value, best_moves, done, .. } =
            try!(self.searcher.try_recv_report());
        let searched_nodes = self.previously_searched_nodes + searched_nodes;
        let depth = if done && !self.search_is_terminated {
            self.previously_searched_nodes = searched_nodes;
            self.value = value;
            if self.widen_aspiration_window() {
                // Start a re-search.
                self.start_aspirated_search();
                return Err(TryRecvError::Empty);
            }
            depth
        } else {
            0
        };

        return Ok(Report {
            search_id: self.search_id,
            searched_nodes: searched_nodes,
            depth: depth,
            value: self.value,
            best_moves: best_moves,
            done: done,
        });
    }

    fn terminate_search(&mut self) {
        self.search_is_terminated = true;
        self.searcher.terminate_search();
    }
}

/// Executes deepeing multi-PV searches with aspiration.
pub struct DeepeningSearcher {
    thread: Option<thread::JoinHandle<()>>,
    thread_commands: Sender<Command>,
    thread_reports: Receiver<Report>,
}

impl SearchExecutor for DeepeningSearcher {
    fn new(tt: Arc<Tt>) -> DeepeningSearcher {
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        DeepeningSearcher {
            thread: Some(thread::spawn(move || {
                serve_deepening(tt, commands_rx, reports_tx);
            })),
            thread_commands: commands_tx,
            thread_reports: reports_rx,
        }
    }

    #[allow(unused_variables)]
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);
        self.thread_commands
            .send(Command::Search {
                search_id: search_id,
                position: position,
                depth: depth,
                lower_bound: lower_bound,
                upper_bound: upper_bound,
            })
            .unwrap();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        self.thread_reports.try_recv()
    }

    fn terminate_search(&mut self) {
        self.thread_commands.send(Command::Stop).unwrap();
    }
}

impl Drop for DeepeningSearcher {
    fn drop(&mut self) {
        self.thread_commands.send(Command::Exit).unwrap();
        self.thread.take().unwrap().join().unwrap();
    }
}
<|endoftext|>


<commit_before>use crossbeam::channel::{unbounded, Receiver, Sender};
use log::error;
use std::net::{TcpListener, TcpStream};
use std::thread;

pub fn iterate(listener: TcpListener, tag: String) -> (Raii, TcpConnectionIterator) {
    let (tx, rx) = unbounded();
    let killer = Raii { killer: tx.clone() };
    thread::spawn(move || listener_thread(&listener, &tag, &tx));
    (killer, TcpConnectionIterator { listener: rx })
}

fn listener_thread(connections: &TcpListener, tag: &str, out: &Sender<Option<TcpStream>>) {
    for stream in connections.incoming() {
        match stream {
            Ok(stream) => {
                if out.send(Some(stream)).is_err() {
                    break;
                }
            }
            Err(err) => {
                error!("TCP connection failed at {}: {}", tag, err);
            }
        }
    }
}

pub struct TcpConnectionIterator {
    listener: Receiver<Option<TcpStream>>,
}

impl Iterator for TcpConnectionIterator {
    type Item = TcpStream;

    fn next(&mut self) -> Option<Self::Item> {
        self.listener.recv().unwrap_or(None)
    }
}

pub struct Raii {
    killer: Sender<Option<TcpStream>>,
}

impl Drop for Raii {
    fn drop(&mut self) {
        if self.killer.send(None).is_err() {
            error!("TCP connection listener has already been killed");
        }
    }
}
<commit_msg>Use channel selection syntax for TCP connection receiver<commit_after>use crossbeam::channel::{bounded, select, unbounded, Receiver, Sender};
use log::error;
use std::net::{TcpListener, TcpStream};
use std::thread;

pub fn iterate(listener: TcpListener, tag: String) -> (Raii, TcpConnectionIterator) {
    let (tcp_stream_tx, tcp_stream_rx) = unbounded();
    let (kill_tx, kill_rx) = bounded(0);
    let killer = Raii { kill_tx };
    thread::spawn(move || listener_thread(&listener, &tag, &tcp_stream_tx));
    (
        killer,
        TcpConnectionIterator {
            tcp_stream_rx,
            kill_rx,
        },
    )
}

fn listener_thread(connections: &TcpListener, tag: &str, out: &Sender<TcpStream>) {
    for stream in connections.incoming() {
        match stream {
            Ok(stream) => {
                if out.send(stream).is_err() {
                    break;
                }
            }
            Err(err) => {
                error!("TCP connection failed at {}: {}", tag, err);
            }
        }
    }
}

pub struct TcpConnectionIterator {
    tcp_stream_rx: Receiver<TcpStream>,
    kill_rx: Receiver<()>,
}

impl Iterator for TcpConnectionIterator {
    type Item = TcpStream;

    fn next(&mut self) -> Option<Self::Item> {
        select! {
            recv(self.tcp_stream_rx) -> msg => msg.ok(),
            recv(self.kill_rx) -> _ => None,
        }
    }
}

pub struct Raii {
    kill_tx: Sender<()>,
}

impl Drop for Raii {
    fn drop(&mut self) {
        let send_result = self.kill_tx.send(());
        if send_result.is_err() {
            error!("TCP connection listener has already been killed");
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::hash::Hash;
use std::rc::Rc;
use std::cell::{RefCell, Ref};
use std::fmt::Display;

struct Rlru<K, V>
    where K: Eq + Hash + Clone
{
    cache: HashMap<K, Rc<RefCell<Node<V>>>>,
    head: Link<V>,
    tail: Link<V>,
    max_length: u32,
}

struct Node<T> {
    elem: T,
    prev: Link<T>,
    next: Link<T>,
}

impl<T> Node<T> {
    fn new(elem: T) -> Self {
        Node {
            elem: elem,
            prev: None,
            next: None,
        }
    }
}

type Link<T> = Option<Rc<RefCell<Node<T>>>>;

impl<K, V> Rlru<K, V>
    where K: Eq + Hash + Clone,
          V: Display
{
    pub fn new() -> Self {
        Rlru {
            cache: HashMap::new(),
            head: None,
            tail: None,
            max_length: 0,
        }
    }

    fn length_upkeep(&mut self) -> &mut Self {
        match self.cache.len() {
            len if len < self.max_length as usize => self,
            // placeholder. Will pop off LRU key.
            _ => self
        }
    }

    fn splice_node(&mut self, node: Rc<RefCell<Node<V>>>, push_front: bool) {
        // update node's prev/next pointers to link to each other
        {
            let mut node = node.borrow_mut();

            // First we use cloning via Rc pointers, but will clean up our references via 'take' in the next_node routine
            node.prev.clone().map(|prev_node| {
                prev_node.borrow_mut().next = node.next.clone();
            });

            // here we take the extracted node's remaining pointers.
            node.next.take().map(|next_node| {
                next_node.borrow_mut().prev = node.prev.take();
            });
        }

        // insert node at head of rlru.
        if push_front {
            self.push(node);
        }
    }

    fn push(&mut self, node: Rc<RefCell<Node<V>>>) -> &mut Self {
        self.head.take().map(|prev_head| {
            prev_head.borrow_mut().prev = Some(node.clone());
            node.borrow_mut().next = Some(prev_head);
        });
        self.head = Some(node.clone());
        self.length_upkeep();
        self
    }

    fn pop(&mut self) -> Option<V> {
        self.tail.take().map(|node| {
            if node.borrow().prev.is_none() {
                // have to worry about updating head.
                self.head.take();
            }
            self.tail = node.borrow_mut().prev.take();
            let mut node = Rc::try_unwrap(node);
            let mut node = node.ok().unwrap().into_inner();
            node.elem
        })
    }

    pub fn get(&mut self, key: &K) -> Option<Ref<V>> {
        // Update node positions
        self.cache.get(key)
            .map(|node| node.clone())
            .map(|node| self.splice_node(node, true));

        // Return the ref.
        self.cache.get(key)
            .map(|node| {
                Ref::map(node.borrow(), |node| &node.elem)
            })
    }

    pub fn set(&mut self, key: K, elem: V) -> &mut Self {
        let mut new_node = Node::new(elem);

        self.cache.remove(&key)
            .map(|old_node| {
                self.splice_node(old_node, false);
            });

        new_node.next = self.head.take();
        let new_node = Rc::new(RefCell::new(new_node));
        self.push(new_node.clone());

        // update tail, assuming this is the only node.
        if self.tail.is_none() {
            self.tail = Some(new_node.clone());
        }

        self.cache.insert(key, new_node);
        self
    }
}

mod test {
    use super::Rlru;

    #[test]
    fn basics() {
        let mut lru = Rlru::new();

        lru.set("a", 1)
            .set("b", 2)
            .set("c", 3);

        assert_eq!(lru.tail.is_some(), true);

        lru.tail.take().map(|node| {
            assert_eq!(node.borrow().elem, 1);
            //replace
            lru.tail = Some(node);
        });

        let second = lru.get(&"b")
            .map(|x| *x);
        assert_eq!(second, Some(2));

        assert_eq!(lru.head.is_some(), true);

        lru.head.take().map(|node| {
            assert_eq!(node.borrow().elem, 2);
        });

    }
}
<commit_msg>into_iter for lru<commit_after>use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::hash::Hash;
use std::rc::Rc;
use std::cell::{RefCell, Ref};
use std::fmt::Display;

struct Rlru<K, V>
    where K: Eq + Hash + Clone
{
    cache: HashMap<K, Rc<RefCell<Node<V>>>>,
    head: Link<V>,
    tail: Link<V>,
    max_length: u32,
}

struct Node<T> {
    elem: T,
    prev: Link<T>,
    next: Link<T>,
}

impl<T> Node<T> {
    fn new(elem: T) -> Self {
        Node {
            elem: elem,
            prev: None,
            next: None,
        }
    }
}

type Link<T> = Option<Rc<RefCell<Node<T>>>>;

impl<K, V> Rlru<K, V>
    where K: Eq + Hash + Clone,
          V: Display
{
    pub fn new() -> Self {
        Rlru {
            cache: HashMap::new(),
            head: None,
            tail: None,
            max_length: 0,
        }
    }

    fn length_upkeep(&mut self) -> &mut Self {
        match self.cache.len() {
            len if len < self.max_length as usize => self,
            // placeholder. Will pop off LRU key.
            _ => self
        }
    }

    fn splice_node(&mut self, node: Rc<RefCell<Node<V>>>, push_front: bool) {
        // update node's prev/next pointers to link to each other
        {
            let mut node = node.borrow_mut();

            // First we use cloning via Rc pointers, but will clean up our references via 'take' in the next_node routine
            node.prev.clone().map(|prev_node| {
                prev_node.borrow_mut().next = node.next.clone();
            });

            // here we take the extracted node's remaining pointers.
            node.next.take().map(|next_node| {
                next_node.borrow_mut().prev = node.prev.take();
            });
        }

        // insert node at head of rlru.
        if push_front {
            self.push(node);
        }
    }

    fn push(&mut self, node: Rc<RefCell<Node<V>>>) -> &mut Self {
        self.head.take().map(|prev_head| {
            prev_head.borrow_mut().prev = Some(node.clone());
            node.borrow_mut().next = Some(prev_head);
        });
        self.head = Some(node.clone());
        self.length_upkeep();
        self
    }

    fn pop(&mut self) -> Option<V> {
        self.tail.take().map(|node| {
            if node.borrow().prev.is_none() {
                // have to worry about updating head.
                self.head.take();
            }
            self.tail = node.borrow_mut().prev.take();
            let mut node = Rc::try_unwrap(node);
            let mut node = node.ok().unwrap().into_inner();
            node.elem
        })
    }

    pub fn get(&mut self, key: &K) -> Option<Ref<V>> {
        // Update node positions
        self.cache.get(key)
            .map(|node| node.clone())
            .map(|node| self.splice_node(node, true));

        // Return the ref.
        self.cache.get(key)
            .map(|node| {
                Ref::map(node.borrow(), |node| &node.elem)
            })
    }

    pub fn set(&mut self, key: K, elem: V) -> &mut Self {
        let mut new_node = Node::new(elem);

        self.cache.remove(&key)
            .map(|old_node| {
                self.splice_node(old_node, false);
            });

        new_node.next = self.head.take();
        let new_node = Rc::new(RefCell::new(new_node));
        self.push(new_node.clone());

        // update tail, assuming this is the only node.
        if self.tail.is_none() {
            self.tail = Some(new_node.clone());
        }

        self.cache.insert(key, new_node);
        self
    }

    // Iterator
    pub fn into_iter(mut self) -> IntoIter<V> {
        self.cache.clear();
        IntoIter {
            next: self.head
        }
    }
}

pub struct IntoIter<T> {
    next: Link<T>
}

impl<T> Iterator for IntoIter<T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        self.next.take()
            .map(|node| {
                node.borrow_mut().next.take().map(|next_node| {
                    // reach next node, removing ref to cur.
                    next_node.borrow_mut().prev.take();
                    self.next = Some(next_node);
                });

                Rc::try_unwrap(node)
                    .ok()
                    .map(|node| {
                        node.into_inner().elem
                    })
                    .unwrap()
            })
    }
}

mod test {
    use super::Rlru;

    #[test]
    fn basics() {
        let mut lru = Rlru::new();

        lru.set("a", 1)
            .set("b", 2)
            .set("c", 3);

        assert_eq!(lru.tail.is_some(), true);

        lru.tail.take().map(|node| {
            assert_eq!(node.borrow().elem, 1);
            //replace
            lru.tail = Some(node);
        });

        let second = lru.get(&"b")
            .map(|x| *x);
        assert_eq!(second, Some(2));

        assert_eq!(lru.head.is_some(), true);

        lru.head.take().map(|node| {
            assert_eq!(node.borrow().elem, 2);
        });

    }

    #[test]
    fn into_iter() {
        let mut lru = Rlru::new();

        lru.set("a", 1)
            .set("b", 2)
            .set("c", 3);

        let mut iter = lru.into_iter();
        let innards = iter.collect::<Vec<_>>();
        assert_eq!(innards, [3, 2, 1]);
    }
}
<|endoftext|>


<commit_before>extern crate toml;
extern crate serde_json;
use std::io;
use std::io::prelude::*;
// use serde_json::Value;

fn main() {
    let stdin = io::stdin();
    let mut string = String::new();
    stdin.lock().read_to_string(&mut string).expect("Error reading stdin");
    let value: serde_json::Value = serde_json::from_str(&string).expect("Error parsing JSON");
    let encoded = toml::to_string_pretty(&value).expect("Error encoding TOML");
    println!("{}", encoded);
}
<commit_msg>Remove commented out use statement<commit_after>extern crate toml;
extern crate serde_json;
use std::io;
use std::io::prelude::*;

fn main() {
    let stdin = io::stdin();
    let mut string = String::new();
    stdin.lock().read_to_string(&mut string).expect("Error reading stdin");
    let value: serde_json::Value = serde_json::from_str(&string).expect("Error parsing JSON");
    let encoded = toml::to_string_pretty(&value).expect("Error encoding TOML");
    println!("{}", encoded);
}
<|endoftext|>


<commit_before>// Copyright 2015 Vadim Nazarov.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Various subroutines for computing a distance between sequences.
<commit_msg>filling up hamm_dist<commit_after>// Copyright 2015 Vadim Nazarov.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Various subroutines for computing a distance between sequences.

use std::iter::Zip;

pub fn hamm_dist(alpha: &[u8], beta: &[u8]) -> Result<u32, bool> {
    if alpha.len() != beta.len() {
        Result(0, true)
    } else {
        let mut score : u32 = 0;
        for (a, b) in Zip::new(alpha, beta) {
            score += alpha == beta;
        }
        Result(score, false)
    }
}

pub fn lev_dist(alpha: &[u8], beta: &[u8]) -> u32 {

}

#[cfg(test)]
mod tests {

    #[test]
    fn test_hamming_dist() {
        // let x = b"GACTATATCG";
        // let y = b"TTTAGCTAGC";
        // // GTCTGCATGC
        // //  |  ||  ||
        // // TTTAGCTAGC
        // assert_eq!(hamm_dist(x, y), 5)

        assert!(true)
    }

    #[test]
    fn test_levenshtein_dist() {
        // let x = b"ACCGTGGAT";
        // let y = b"AAAAACCGTTGAT";
        // // ----ACCGTGGAT
        // //     ||||| |||
        // // AAAAACCGTTGAT
        // assert_eq!(lev_dist(x, y), align_global!(x, y, -1, 1, |a: u8, b: u8| if a == b {1i32} else {-1i32}))

        assert!(true)
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::cell::RefCell;
use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex};
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;

use WindowAttributes;
use CursorState;
use Event;
use super::event;
use super::WindowState;

use user32;
use shell32;
use winapi;

/// There's no parameters passed to the callback function, so it needs to get
/// its context (the HWND, the Sender for events, etc.) stashed in
/// a thread-local variable.
thread_local!(pub static CONTEXT_STASH: RefCell<Option<ThreadLocalData>> = RefCell::new(None));

pub struct ThreadLocalData {
    pub win: winapi::HWND,
    pub sender: Sender<Event>,
    pub window_state: Arc<Mutex<WindowState>>
}

struct MinMaxInfo {
    reserved: winapi::POINT, // Do not use/change
    max_size: winapi::POINT,
    max_position: winapi::POINT,
    min_track: winapi::POINT,
    max_track: winapi::POINT
}

/// Checks that the window is the good one, and if so send the event to it.
fn send_event(input_window: winapi::HWND, event: Event) {
    CONTEXT_STASH.with(|context_stash| {
        let context_stash = context_stash.borrow();
        let stored = match *context_stash {
            None => return,
            Some(ref v) => v
        };

        let &ThreadLocalData { ref win, ref sender, .. } = stored;

        if win != &input_window {
            return;
        }

        sender.send(event).ok();  // ignoring if closed
    });
}

/// This is the callback that is called by `DispatchMessage` in the events loop.
///
/// Returning 0 tells the Win32 API that the message has been processed.
// FIXME: detect WM_DWMCOMPOSITIONCHANGED and call DwmEnableBlurBehindWindow if necessary
pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
                                       wparam: winapi::WPARAM, lparam: winapi::LPARAM)
                                       -> winapi::LRESULT
{
    match msg {
        winapi::WM_DESTROY => {
            use events::Event::Closed;

            CONTEXT_STASH.with(|context_stash| {
                let context_stash = context_stash.borrow();
                let stored = match *context_stash {
                    None => return,
                    Some(ref v) => v
                };

                let &ThreadLocalData { ref win, .. } = stored;

                if win == &window {
                    user32::PostQuitMessage(0);
                }
            });

            send_event(window, Closed);
            0
        },

        winapi::WM_ERASEBKGND => {
            1
        },

        winapi::WM_SIZE => {
            use events::Event::Resized;
            let w = winapi::LOWORD(lparam as winapi::DWORD) as u32;
            let h = winapi::HIWORD(lparam as winapi::DWORD) as u32;
            send_event(window, Resized(w, h));
            0
        },

        winapi::WM_MOVE => {
            use events::Event::Moved;
            let x = winapi::LOWORD(lparam as winapi::DWORD) as i32;
            let y = winapi::HIWORD(lparam as winapi::DWORD) as i32;
            send_event(window, Moved(x, y));
            0
        },

        winapi::WM_CHAR => {
            use std::mem;
            use events::Event::ReceivedCharacter;
            let chr: char = mem::transmute(wparam as u32);
            send_event(window, ReceivedCharacter(chr));
            0
        },

        // Prevents default windows menu hotkeys playing unwanted
        // "ding" sounds. Alternatively could check for WM_SYSCOMMAND
        // with wparam being SC_KEYMENU, but this may prevent some
        // other unwanted default hotkeys as well.
        winapi::WM_SYSCHAR => {
            0
        }

        winapi::WM_MOUSEMOVE => {
            use events::Event::MouseMoved;

            let x = winapi::GET_X_LPARAM(lparam) as i32;
            let y = winapi::GET_Y_LPARAM(lparam) as i32;

            send_event(window, MouseMoved((x, y)));

            0
        },

        winapi::WM_MOUSEWHEEL => {
            use events::Event::MouseWheel;
            use events::MouseScrollDelta::LineDelta;

            let value = (wparam >> 16) as i16;
            let value = value as i32;
            let value = value as f32 / winapi::WHEEL_DELTA as f32;

            send_event(window, MouseWheel(LineDelta(0.0, value)));

            0
        },

        winapi::WM_KEYDOWN | winapi::WM_SYSKEYDOWN => {
            use events::Event::KeyboardInput;
            use events::ElementState::Pressed;
            if msg == winapi::WM_SYSKEYDOWN && wparam as i32 == winapi::VK_F4 {
                user32::DefWindowProcW(window, msg, wparam, lparam)
            } else {
                let (scancode, vkey) = event::vkeycode_to_element(wparam, lparam);
                send_event(window, KeyboardInput(Pressed, scancode, vkey));
                0
            }
        },

        winapi::WM_KEYUP | winapi::WM_SYSKEYUP => {
            use events::Event::KeyboardInput;
            use events::ElementState::Released;
            let (scancode, vkey) = event::vkeycode_to_element(wparam, lparam);
            send_event(window, KeyboardInput(Released, scancode, vkey));
            0
        },

        winapi::WM_LBUTTONDOWN => {
            use events::Event::MouseInput;
            use events::MouseButton::Left;
            use events::ElementState::Pressed;
            send_event(window, MouseInput(Pressed, Left));
            0
        },

        winapi::WM_LBUTTONUP => {
            use events::Event::MouseInput;
            use events::MouseButton::Left;
            use events::ElementState::Released;
            send_event(window, MouseInput(Released, Left));
            0
        },

        winapi::WM_RBUTTONDOWN => {
            use events::Event::MouseInput;
            use events::MouseButton::Right;
            use events::ElementState::Pressed;
            send_event(window, MouseInput(Pressed, Right));
            0
        },

        winapi::WM_RBUTTONUP => {
            use events::Event::MouseInput;
            use events::MouseButton::Right;
            use events::ElementState::Released;
            send_event(window, MouseInput(Released, Right));
            0
        },

        winapi::WM_MBUTTONDOWN => {
            use events::Event::MouseInput;
            use events::MouseButton::Middle;
            use events::ElementState::Pressed;
            send_event(window, MouseInput(Pressed, Middle));
            0
        },

        winapi::WM_MBUTTONUP => {
            use events::Event::MouseInput;
            use events::MouseButton::Middle;
            use events::ElementState::Released;
            send_event(window, MouseInput(Released, Middle));
            0
        },

        winapi::WM_INPUT => {
            let mut data: winapi::RAWINPUT = mem::uninitialized();
            let mut data_size = mem::size_of::<winapi::RAWINPUT>() as winapi::UINT;
            user32::GetRawInputData(mem::transmute(lparam), winapi::RID_INPUT,
                                    mem::transmute(&mut data), &mut data_size,
                                    mem::size_of::<winapi::RAWINPUTHEADER>() as winapi::UINT);

            if data.header.dwType == winapi::RIM_TYPEMOUSE {
                let _x = data.mouse.lLastX;  // FIXME: this is not always the relative movement
                let _y = data.mouse.lLastY;
                // TODO:
                //send_event(window, Event::MouseRawMovement { x: x, y: y });

                0

            } else {
                user32::DefWindowProcW(window, msg, wparam, lparam)
            }
        },

        winapi::WM_SETFOCUS => {
            use events::Event::Focused;
            send_event(window, Focused(true));
            0
        },

        winapi::WM_KILLFOCUS => {
            use events::Event::Focused;
            send_event(window, Focused(false));
            0
        },

        winapi::WM_SETCURSOR => {
            CONTEXT_STASH.with(|context_stash| {
                let cstash = context_stash.borrow();
                let cstash = cstash.as_ref();
                // there's a very bizarre borrow checker bug
                // possibly related to rust-lang/rust/#23338
                let _cursor_state = if let Some(cstash) = cstash {
                    if let Ok(window_state) = cstash.window_state.lock() {
                        match window_state.cursor_state {
                            CursorState::Normal => {
                                user32::SetCursor(user32::LoadCursorW(
                                        ptr::null_mut(),
                                        window_state.cursor));
                            },
                            CursorState::Grab | CursorState::Hide => {
                                user32::SetCursor(ptr::null_mut());
                            }
                        }
                    }
                } else {
                    return
                };

//                let &ThreadLocalData { ref cursor_state, .. } = stored;
            });
            0
        },

        winapi::WM_DROPFILES => {
            use events::Event::DroppedFile;

            let hdrop = wparam as winapi::HDROP;
            let mut pathbuf: [u16; winapi::MAX_PATH] = mem::uninitialized();
            let num_drops = shell32::DragQueryFileW(hdrop, 0xFFFFFFFF, ptr::null_mut(), 0);

            for i in 0..num_drops {
                let nch = shell32::DragQueryFileW(hdrop, i, pathbuf.as_mut_ptr(),
                                                  winapi::MAX_PATH as u32) as usize;
                if nch > 0 {
                    send_event(window, DroppedFile(OsString::from_wide(&pathbuf[0..nch]).into()));
                }
            }

            shell32::DragFinish(hdrop);
            0
        },

        winapi::WM_GETMINMAXINFO => {
            let mut mmi = lparam as *mut MinMaxInfo;
            //(*mmi).max_position = winapi::POINT { x: -8, y: -8 }; // The upper left corner of the window if it were maximized on the primary monitor.
            //(*mmi).max_size = winapi::POINT { x: .., y: .. }; // The dimensions of the primary monitor.

            CONTEXT_STASH.with(|context_stash| {
                match context_stash.borrow().as_ref() {
                    Some(cstash) => {
                        let window_state = cstash.window_state.lock().unwrap();

                        match window_state.attributes.min_dimensions {
                            Some((width, height)) => {
                                (*mmi).min_track = winapi::POINT { x: width as i32, y: height as i32 };
                            },
                            None => { }
                        }

                        match window_state.attributes.max_dimensions {
                            Some((width, height)) => {
                                (*mmi).max_track = winapi::POINT { x: width as i32, y: height as i32 };
                            },
                            None => { }
                        }
                    },
                    None => { }
                }
            });
            0
        },

        x if x == *super::WAKEUP_MSG_ID => {
            use events::Event::Awakened;
            send_event(window, Awakened);
            0
        },

        _ => {
            user32::DefWindowProcW(window, msg, wparam, lparam)
        }
    }
}
<commit_msg>Support for side buttons on mouse<commit_after>use std::mem;
use std::ptr;
use std::cell::RefCell;
use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex};
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;

use WindowAttributes;
use CursorState;
use Event;
use super::event;
use super::WindowState;

use user32;
use shell32;
use winapi;

/// There's no parameters passed to the callback function, so it needs to get
/// its context (the HWND, the Sender for events, etc.) stashed in
/// a thread-local variable.
thread_local!(pub static CONTEXT_STASH: RefCell<Option<ThreadLocalData>> = RefCell::new(None));

pub struct ThreadLocalData {
    pub win: winapi::HWND,
    pub sender: Sender<Event>,
    pub window_state: Arc<Mutex<WindowState>>
}

struct MinMaxInfo {
    reserved: winapi::POINT, // Do not use/change
    max_size: winapi::POINT,
    max_position: winapi::POINT,
    min_track: winapi::POINT,
    max_track: winapi::POINT
}

/// Checks that the window is the good one, and if so send the event to it.
fn send_event(input_window: winapi::HWND, event: Event) {
    CONTEXT_STASH.with(|context_stash| {
        let context_stash = context_stash.borrow();
        let stored = match *context_stash {
            None => return,
            Some(ref v) => v
        };

        let &ThreadLocalData { ref win, ref sender, .. } = stored;

        if win != &input_window {
            return;
        }

        sender.send(event).ok();  // ignoring if closed
    });
}

/// This is the callback that is called by `DispatchMessage` in the events loop.
///
/// Returning 0 tells the Win32 API that the message has been processed.
// FIXME: detect WM_DWMCOMPOSITIONCHANGED and call DwmEnableBlurBehindWindow if necessary
pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
                                       wparam: winapi::WPARAM, lparam: winapi::LPARAM)
                                       -> winapi::LRESULT
{
    match msg {
        winapi::WM_DESTROY => {
            use events::Event::Closed;

            CONTEXT_STASH.with(|context_stash| {
                let context_stash = context_stash.borrow();
                let stored = match *context_stash {
                    None => return,
                    Some(ref v) => v
                };

                let &ThreadLocalData { ref win, .. } = stored;

                if win == &window {
                    user32::PostQuitMessage(0);
                }
            });

            send_event(window, Closed);
            0
        },

        winapi::WM_ERASEBKGND => {
            1
        },

        winapi::WM_SIZE => {
            use events::Event::Resized;
            let w = winapi::LOWORD(lparam as winapi::DWORD) as u32;
            let h = winapi::HIWORD(lparam as winapi::DWORD) as u32;
            send_event(window, Resized(w, h));
            0
        },

        winapi::WM_MOVE => {
            use events::Event::Moved;
            let x = winapi::LOWORD(lparam as winapi::DWORD) as i32;
            let y = winapi::HIWORD(lparam as winapi::DWORD) as i32;
            send_event(window, Moved(x, y));
            0
        },

        winapi::WM_CHAR => {
            use std::mem;
            use events::Event::ReceivedCharacter;
            let chr: char = mem::transmute(wparam as u32);
            send_event(window, ReceivedCharacter(chr));
            0
        },

        // Prevents default windows menu hotkeys playing unwanted
        // "ding" sounds. Alternatively could check for WM_SYSCOMMAND
        // with wparam being SC_KEYMENU, but this may prevent some
        // other unwanted default hotkeys as well.
        winapi::WM_SYSCHAR => {
            0
        }

        winapi::WM_MOUSEMOVE => {
            use events::Event::MouseMoved;

            let x = winapi::GET_X_LPARAM(lparam) as i32;
            let y = winapi::GET_Y_LPARAM(lparam) as i32;

            send_event(window, MouseMoved((x, y)));

            0
        },

        winapi::WM_MOUSEWHEEL => {
            use events::Event::MouseWheel;
            use events::MouseScrollDelta::LineDelta;

            let value = (wparam >> 16) as i16;
            let value = value as i32;
            let value = value as f32 / winapi::WHEEL_DELTA as f32;

            send_event(window, MouseWheel(LineDelta(0.0, value)));

            0
        },

        winapi::WM_KEYDOWN | winapi::WM_SYSKEYDOWN => {
            use events::Event::KeyboardInput;
            use events::ElementState::Pressed;
            if msg == winapi::WM_SYSKEYDOWN && wparam as i32 == winapi::VK_F4 {
                user32::DefWindowProcW(window, msg, wparam, lparam)
            } else {
                let (scancode, vkey) = event::vkeycode_to_element(wparam, lparam);
                send_event(window, KeyboardInput(Pressed, scancode, vkey));
                0
            }
        },

        winapi::WM_KEYUP | winapi::WM_SYSKEYUP => {
            use events::Event::KeyboardInput;
            use events::ElementState::Released;
            let (scancode, vkey) = event::vkeycode_to_element(wparam, lparam);
            send_event(window, KeyboardInput(Released, scancode, vkey));
            0
        },

        winapi::WM_LBUTTONDOWN => {
            use events::Event::MouseInput;
            use events::MouseButton::Left;
            use events::ElementState::Pressed;
            send_event(window, MouseInput(Pressed, Left));
            0
        },

        winapi::WM_LBUTTONUP => {
            use events::Event::MouseInput;
            use events::MouseButton::Left;
            use events::ElementState::Released;
            send_event(window, MouseInput(Released, Left));
            0
        },

        winapi::WM_RBUTTONDOWN => {
            use events::Event::MouseInput;
            use events::MouseButton::Right;
            use events::ElementState::Pressed;
            send_event(window, MouseInput(Pressed, Right));
            0
        },

        winapi::WM_RBUTTONUP => {
            use events::Event::MouseInput;
            use events::MouseButton::Right;
            use events::ElementState::Released;
            send_event(window, MouseInput(Released, Right));
            0
        },

        winapi::WM_MBUTTONDOWN => {
            use events::Event::MouseInput;
            use events::MouseButton::Middle;
            use events::ElementState::Pressed;
            send_event(window, MouseInput(Pressed, Middle));
            0
        },

        winapi::WM_MBUTTONUP => {
            use events::Event::MouseInput;
            use events::MouseButton::Middle;
            use events::ElementState::Released;
            send_event(window, MouseInput(Released, Middle));
            0
        },

        winapi::WM_XBUTTONDOWN => {
            use events::Event::MouseInput;
            use events::MouseButton::Other;
            use events::ElementState::Pressed;
            let xbutton = winapi::HIWORD(wparam as winapi::DWORD) as winapi::c_int; // waiting on PR for winapi to add GET_XBUTTON_WPARAM
            send_event(window, MouseInput(Pressed, Other(xbutton as u8)));
            0
        },

        winapi::WM_XBUTTONUP => {
            use events::Event::MouseInput;
            use events::MouseButton::Other;
            use events::ElementState::Released;
            let xbutton = winapi::HIWORD(wparam as winapi::DWORD) as winapi::c_int;
            send_event(window, MouseInput(Released, Other(xbutton as u8)));
            0
        },

        winapi::WM_INPUT => {
            let mut data: winapi::RAWINPUT = mem::uninitialized();
            let mut data_size = mem::size_of::<winapi::RAWINPUT>() as winapi::UINT;
            user32::GetRawInputData(mem::transmute(lparam), winapi::RID_INPUT,
                                    mem::transmute(&mut data), &mut data_size,
                                    mem::size_of::<winapi::RAWINPUTHEADER>() as winapi::UINT);

            if data.header.dwType == winapi::RIM_TYPEMOUSE {
                let _x = data.mouse.lLastX;  // FIXME: this is not always the relative movement
                let _y = data.mouse.lLastY;
                // TODO:
                //send_event(window, Event::MouseRawMovement { x: x, y: y });

                0

            } else {
                user32::DefWindowProcW(window, msg, wparam, lparam)
            }
        },

        winapi::WM_SETFOCUS => {
            use events::Event::Focused;
            send_event(window, Focused(true));
            0
        },

        winapi::WM_KILLFOCUS => {
            use events::Event::Focused;
            send_event(window, Focused(false));
            0
        },

        winapi::WM_SETCURSOR => {
            CONTEXT_STASH.with(|context_stash| {
                let cstash = context_stash.borrow();
                let cstash = cstash.as_ref();
                // there's a very bizarre borrow checker bug
                // possibly related to rust-lang/rust/#23338
                let _cursor_state = if let Some(cstash) = cstash {
                    if let Ok(window_state) = cstash.window_state.lock() {
                        match window_state.cursor_state {
                            CursorState::Normal => {
                                user32::SetCursor(user32::LoadCursorW(
                                        ptr::null_mut(),
                                        window_state.cursor));
                            },
                            CursorState::Grab | CursorState::Hide => {
                                user32::SetCursor(ptr::null_mut());
                            }
                        }
                    }
                } else {
                    return
                };

//                let &ThreadLocalData { ref cursor_state, .. } = stored;
            });
            0
        },

        winapi::WM_DROPFILES => {
            use events::Event::DroppedFile;

            let hdrop = wparam as winapi::HDROP;
            let mut pathbuf: [u16; winapi::MAX_PATH] = mem::uninitialized();
            let num_drops = shell32::DragQueryFileW(hdrop, 0xFFFFFFFF, ptr::null_mut(), 0);

            for i in 0..num_drops {
                let nch = shell32::DragQueryFileW(hdrop, i, pathbuf.as_mut_ptr(),
                                                  winapi::MAX_PATH as u32) as usize;
                if nch > 0 {
                    send_event(window, DroppedFile(OsString::from_wide(&pathbuf[0..nch]).into()));
                }
            }

            shell32::DragFinish(hdrop);
            0
        },

        winapi::WM_GETMINMAXINFO => {
            let mut mmi = lparam as *mut MinMaxInfo;
            //(*mmi).max_position = winapi::POINT { x: -8, y: -8 }; // The upper left corner of the window if it were maximized on the primary monitor.
            //(*mmi).max_size = winapi::POINT { x: .., y: .. }; // The dimensions of the primary monitor.

            CONTEXT_STASH.with(|context_stash| {
                match context_stash.borrow().as_ref() {
                    Some(cstash) => {
                        let window_state = cstash.window_state.lock().unwrap();

                        match window_state.attributes.min_dimensions {
                            Some((width, height)) => {
                                (*mmi).min_track = winapi::POINT { x: width as i32, y: height as i32 };
                            },
                            None => { }
                        }

                        match window_state.attributes.max_dimensions {
                            Some((width, height)) => {
                                (*mmi).max_track = winapi::POINT { x: width as i32, y: height as i32 };
                            },
                            None => { }
                        }
                    },
                    None => { }
                }
            });
            0
        },

        x if x == *super::WAKEUP_MSG_ID => {
            use events::Event::Awakened;
            send_event(window, Awakened);
            0
        },

        _ => {
            user32::DefWindowProcW(window, msg, wparam, lparam)
        }
    }
}
<|endoftext|>


<commit_before>//! BookmarkCollection module
//!
//! A BookmarkCollection is nothing more than a simple store entry. One can simply call functions
//! from the libimagentrylink::external::ExternalLinker trait on this to generate external links.
//!
//! The BookmarkCollection type offers helper functions to get all links or such things.
use std::ops::Deref;
use std::ops::DerefMut;

use regex::Regex;

use error::BookmarkError as BE;
use error::BookmarkErrorKind as BEK;
use error::MapErrInto;
use result::Result;
use module_path::ModuleEntryPath;

use libimagstore::store::Store;
use libimagstore::storeid::IntoStoreId;
use libimagstore::store::FileLockEntry;
use libimagentrylink::external::ExternalLinker;
use libimagentrylink::internal::InternalLinker;
use libimagentrylink::internal::Link as StoreLink;
use libimagerror::into::IntoError;
use url::Url;

use link::Link;

pub struct BookmarkCollection<'a> {
    fle: FileLockEntry<'a>,
    store: &'a Store,
}

/// {Internal, External}Linker is implemented as Deref is implemented
impl<'a> Deref for BookmarkCollection<'a> {
    type Target = FileLockEntry<'a>;

    fn deref(&self) -> &FileLockEntry<'a> {
        &self.fle
    }

}

impl<'a> DerefMut for BookmarkCollection<'a> {

    fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
        &mut self.fle
    }

}

impl<'a> BookmarkCollection<'a> {

    pub fn new(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
        let id = ModuleEntryPath::new(name).into_storeid();
        store.create(id)
            .map(|fle| {
                BookmarkCollection {
                    fle: fle,
                    store: store,
                }
            })
            .map_err_into(BEK::StoreReadError)
    }

    pub fn get(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
        let id = ModuleEntryPath::new(name).into_storeid();
        store.get(id)
            .map_err_into(BEK::StoreReadError)
            .and_then(|fle| {
                match fle {
                    None => Err(BEK::CollectionNotFound.into_error()),
                    Some(e) => Ok(BookmarkCollection {
                        fle: e,
                        store: store,
                    }),
                }
            })
    }

    pub fn delete(store: &Store, name: &str) -> Result<()> {
        store.delete(ModuleEntryPath::new(name).into_storeid()).map_err_into(BEK::StoreReadError)
    }

    pub fn links(&self) -> Result<Vec<Url>> {
        self.fle.get_external_links(&self.store).map_err_into(BEK::LinkError)
    }

    pub fn link_entries(&self) -> Result<Vec<StoreLink>> {
        use libimagentrylink::external::is_external_link_storeid;

        self.fle
            .get_internal_links()
            .map(|v| v.into_iter().filter(|id| is_external_link_storeid(id)).collect())
            .map_err_into(BEK::StoreReadError)
    }

    pub fn add_link(&mut self, l: Link) -> Result<()> {
        use link::IntoUrl;

        l.into_url()
            .and_then(|url| self.add_external_link(self.store, url).map_err_into(BEK::LinkingError))
            .map_err_into(BEK::LinkError)
    }

    pub fn get_links_matching(&self, r: Regex) -> Result<Link> {
        unimplemented!()
    }

    pub fn remove_link(&self, l: Link) -> Result<()> {
        unimplemented!()
    }

}

<commit_msg>Impl BookmarkCollection::get_links_matching()<commit_after>//! BookmarkCollection module
//!
//! A BookmarkCollection is nothing more than a simple store entry. One can simply call functions
//! from the libimagentrylink::external::ExternalLinker trait on this to generate external links.
//!
//! The BookmarkCollection type offers helper functions to get all links or such things.
use std::ops::Deref;
use std::ops::DerefMut;

use regex::Regex;

use error::BookmarkError as BE;
use error::BookmarkErrorKind as BEK;
use error::MapErrInto;
use result::Result;
use module_path::ModuleEntryPath;

use libimagstore::store::Store;
use libimagstore::storeid::IntoStoreId;
use libimagstore::store::FileLockEntry;
use libimagentrylink::external::ExternalLinker;
use libimagentrylink::internal::InternalLinker;
use libimagentrylink::internal::Link as StoreLink;
use libimagerror::into::IntoError;
use url::Url;

use link::Link;

pub struct BookmarkCollection<'a> {
    fle: FileLockEntry<'a>,
    store: &'a Store,
}

/// {Internal, External}Linker is implemented as Deref is implemented
impl<'a> Deref for BookmarkCollection<'a> {
    type Target = FileLockEntry<'a>;

    fn deref(&self) -> &FileLockEntry<'a> {
        &self.fle
    }

}

impl<'a> DerefMut for BookmarkCollection<'a> {

    fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
        &mut self.fle
    }

}

impl<'a> BookmarkCollection<'a> {

    pub fn new(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
        let id = ModuleEntryPath::new(name).into_storeid();
        store.create(id)
            .map(|fle| {
                BookmarkCollection {
                    fle: fle,
                    store: store,
                }
            })
            .map_err_into(BEK::StoreReadError)
    }

    pub fn get(store: &'a Store, name: &str) -> Result<BookmarkCollection<'a>> {
        let id = ModuleEntryPath::new(name).into_storeid();
        store.get(id)
            .map_err_into(BEK::StoreReadError)
            .and_then(|fle| {
                match fle {
                    None => Err(BEK::CollectionNotFound.into_error()),
                    Some(e) => Ok(BookmarkCollection {
                        fle: e,
                        store: store,
                    }),
                }
            })
    }

    pub fn delete(store: &Store, name: &str) -> Result<()> {
        store.delete(ModuleEntryPath::new(name).into_storeid()).map_err_into(BEK::StoreReadError)
    }

    pub fn links(&self) -> Result<Vec<Url>> {
        self.fle.get_external_links(&self.store).map_err_into(BEK::LinkError)
    }

    pub fn link_entries(&self) -> Result<Vec<StoreLink>> {
        use libimagentrylink::external::is_external_link_storeid;

        self.fle
            .get_internal_links()
            .map(|v| v.into_iter().filter(|id| is_external_link_storeid(id)).collect())
            .map_err_into(BEK::StoreReadError)
    }

    pub fn add_link(&mut self, l: Link) -> Result<()> {
        use link::IntoUrl;

        l.into_url()
            .and_then(|url| self.add_external_link(self.store, url).map_err_into(BEK::LinkingError))
            .map_err_into(BEK::LinkError)
    }

    pub fn get_links_matching(&self, r: Regex) -> Result<Option<Link>> {
        self.get_external_links(self.store)
            .map_err_into(BEK::LinkError)
            .map(|v| {
                v.into_iter()
                    .map(Url::into_string)
                    .filter(|urlstr| r.is_match(&urlstr[..]))
                    .map(Link::from)
                    .next()
            })
    }

    pub fn remove_link(&self, l: Link) -> Result<()> {
        unimplemented!()
    }

}

<|endoftext|>


<commit_before>//! Encoding and decoding of the (16, 8, 5) shortened cyclic code described by P25.
//!
//! The parity-check matrix construction was sourced from \[1] and the decoding algorithm
//! was derived from \[2]. The key information that this code is shortened from a (17, 8,
//! 5) code came from \[3].
//!
//! \[1]: "Coding Theory and Cryptography: The Essentials", 2nd ed, Hankerson, Hoffman, et
//! al, 2000
//! \[2]: "Error Control Coding", Lin and Costello, 1983
//! \[3]: "Standard APCO25 Physical Layer of the Radio Transmission Chain", Simon, 2014

/// Encode the 8 data bits into a 16-bit codeword.
pub fn encode(data: u8) -> u16 {
    matrix_mul_systematic!(data, GEN, u16)
}

/// Try to decode the 16-bit word to the nearest codeword, correcting up to 2 errors.
/// Return `Some((data, err))`, where `data` are the 12 data bits and `err` is the number
/// of errors corrected, on success and `None` on a detected unrecoverable error.
pub fn decode(word: u16) -> Option<(u8, usize)> {
    // Go through a full cycle of the codeword, so the data bits end up in their original
    // position. The word is expanded to 32 bits so it can be treated as the 17-bit word
    // the shortened code is derived from.
    let (fixed, word) = (0..17).fold((Some(0), word as u32), |(fixed, word), _| {
        let syn = matrix_mul!(word, PAR, u8);

        if syn == 0 {
            return (fixed, rotate_17(word));
        }

        match pattern(syn) {
            Some(pat) => (Some(pat.count_ones()), rotate_17(word ^ pat)),
            None => (None, rotate_17(word)),
        }
    });

    match fixed {
        Some(err) => Some(((word >> 8) as u8, err as usize)),
        None => None,
    }
}

/// Transposed generator matrix.
const GEN: [u8; 8] = [
    0b00111100,
    0b10011110,
    0b01001111,
    0b00011011,
    0b10110001,
    0b11100100,
    0b11110010,
    0b01111001,
];

/// Transposed parity-check matrix, where the rows of the original are generated from x^i
/// mod g(x).
const PAR: [u32; 8] = [
    0b10000000100111100,
    0b01000000010011110,
    0b00100000001001111,
    0b00010000100011011,
    0b00001000110110001,
    0b00000100111100100,
    0b00000010011110010,
    0b00000001001111001,
];

/// Find the error pattern associated with the syndrome.
///
/// One of the benefits of the cyclic algorithm is we only have to store error patterns
/// with the LSB set.
fn pattern(syn: u8) -> Option<u32> {
    match syn {
        0b00011001 => Some(0b00100000000000001),
        0b00011110 => Some(0b00000000001000001),
        0b00101001 => Some(0b00010000000000001),
        0b00110001 => Some(0b00001000000000001),
        0b00111000 => Some(0b00000001000000001),
        0b00111001 => Some(0b00000000000000001),
        0b00111011 => Some(0b00000010000000001),
        0b00111101 => Some(0b00000100000000001),
        0b01001011 => Some(0b00000000000000011),
        0b01110111 => Some(0b00000000010000001),
        0b01111001 => Some(0b01000000000000001),
        0b10100101 => Some(0b00000000100000001),
        0b10110110 => Some(0b00000000000100001),
        0b10111001 => Some(0b10000000000000001),
        0b11001000 => Some(0b00000000000001001),
        0b11011101 => Some(0b00000000000000101),
        0b11100010 => Some(0b00000000000010001),
        _ => None,
    }
}

/// Cyclically rotate the word as if it was 17 bits long.
fn rotate_17(word: u32) -> u32 {
    let lsb = word & 1;
    word >> 1 | lsb << 16
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_decode() {
        let w = 0b10101011;
        let e = encode(w);

        assert_eq!(Some((w, 0)), decode(e^0b0000000000000000));
        assert_eq!(Some((w, 2)), decode(e^0b1000000000000001));
        assert_eq!(Some((w, 1)), decode(e^0b0001000000000000));
        assert_eq!(Some((w, 2)), decode(e^0b0011000000000000));

        assert_eq!(Some((w, 1)), decode(e^0b1000000000000000));
        assert_eq!(Some((w, 1)), decode(e^0b0100000000000000));
        assert_eq!(Some((w, 2)), decode(e^0b0010000000000001));
        assert_eq!(Some((w, 2)), decode(e^0b0001000000000010));
        assert_eq!(Some((w, 2)), decode(e^0b0000100000000100));
        assert_eq!(Some((w, 2)), decode(e^0b0000010000001000));
        assert_eq!(Some((w, 2)), decode(e^0b0000001000010000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000100100000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000011000000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000001010000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000010001000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000100000100));
        assert_eq!(Some((w, 2)), decode(e^0b0000001000000010));
        assert_eq!(Some((w, 2)), decode(e^0b0000010000000001));
        assert_eq!(Some((w, 1)), decode(e^0b0000100000000000));
        assert_eq!(Some((w, 1)), decode(e^0b0001000000000000));
        assert_eq!(Some((w, 2)), decode(e^0b0010000000000001));
        assert_eq!(Some((w, 2)), decode(e^0b0100000000000100));
        assert_eq!(Some((w, 2)), decode(e^0b1000000000001000));

        for i in 0..1u16<<8 {
            assert_eq!(decode(encode(i as u8)).unwrap().0, i as u8);
        }
    }
}
<commit_msg>s/syn/syndrome/<commit_after>//! Encoding and decoding of the (16, 8, 5) shortened cyclic code described by P25.
//!
//! The parity-check matrix construction was sourced from \[1] and the decoding algorithm
//! was derived from \[2]. The key information that this code is shortened from a (17, 8,
//! 5) code came from \[3].
//!
//! \[1]: "Coding Theory and Cryptography: The Essentials", 2nd ed, Hankerson, Hoffman, et
//! al, 2000
//! \[2]: "Error Control Coding", Lin and Costello, 1983
//! \[3]: "Standard APCO25 Physical Layer of the Radio Transmission Chain", Simon, 2014

/// Encode the 8 data bits into a 16-bit codeword.
pub fn encode(data: u8) -> u16 {
    matrix_mul_systematic!(data, GEN, u16)
}

/// Try to decode the 16-bit word to the nearest codeword, correcting up to 2 errors.
/// Return `Some((data, err))`, where `data` are the 12 data bits and `err` is the number
/// of errors corrected, on success and `None` on a detected unrecoverable error.
pub fn decode(word: u16) -> Option<(u8, usize)> {
    // Go through a full cycle of the codeword, so the data bits end up in their original
    // position. The word is expanded to 32 bits so it can be treated as the 17-bit word
    // the shortened code is derived from.
    let (fixed, word) = (0..17).fold((Some(0), word as u32), |(fixed, word), _| {
        let syndrome = matrix_mul!(word, PAR, u8);

        if syndrome == 0 {
            return (fixed, rotate_17(word));
        }

        match pattern(syndrome) {
            Some(pat) => (Some(pat.count_ones()), rotate_17(word ^ pat)),
            None => (None, rotate_17(word)),
        }
    });

    match fixed {
        Some(err) => Some(((word >> 8) as u8, err as usize)),
        None => None,
    }
}

/// Transposed generator matrix.
const GEN: [u8; 8] = [
    0b00111100,
    0b10011110,
    0b01001111,
    0b00011011,
    0b10110001,
    0b11100100,
    0b11110010,
    0b01111001,
];

/// Transposed parity-check matrix, where the rows of the original are generated from x^i
/// mod g(x).
const PAR: [u32; 8] = [
    0b10000000100111100,
    0b01000000010011110,
    0b00100000001001111,
    0b00010000100011011,
    0b00001000110110001,
    0b00000100111100100,
    0b00000010011110010,
    0b00000001001111001,
];

/// Find the error pattern associated with the syndrome.
///
/// One of the benefits of the cyclic algorithm is we only have to store error patterns
/// with the LSB set.
fn pattern(syn: u8) -> Option<u32> {
    match syn {
        0b00011001 => Some(0b00100000000000001),
        0b00011110 => Some(0b00000000001000001),
        0b00101001 => Some(0b00010000000000001),
        0b00110001 => Some(0b00001000000000001),
        0b00111000 => Some(0b00000001000000001),
        0b00111001 => Some(0b00000000000000001),
        0b00111011 => Some(0b00000010000000001),
        0b00111101 => Some(0b00000100000000001),
        0b01001011 => Some(0b00000000000000011),
        0b01110111 => Some(0b00000000010000001),
        0b01111001 => Some(0b01000000000000001),
        0b10100101 => Some(0b00000000100000001),
        0b10110110 => Some(0b00000000000100001),
        0b10111001 => Some(0b10000000000000001),
        0b11001000 => Some(0b00000000000001001),
        0b11011101 => Some(0b00000000000000101),
        0b11100010 => Some(0b00000000000010001),
        _ => None,
    }
}

/// Cyclically rotate the word as if it was 17 bits long.
fn rotate_17(word: u32) -> u32 {
    let lsb = word & 1;
    word >> 1 | lsb << 16
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_decode() {
        let w = 0b10101011;
        let e = encode(w);

        assert_eq!(Some((w, 0)), decode(e^0b0000000000000000));
        assert_eq!(Some((w, 2)), decode(e^0b1000000000000001));
        assert_eq!(Some((w, 1)), decode(e^0b0001000000000000));
        assert_eq!(Some((w, 2)), decode(e^0b0011000000000000));

        assert_eq!(Some((w, 1)), decode(e^0b1000000000000000));
        assert_eq!(Some((w, 1)), decode(e^0b0100000000000000));
        assert_eq!(Some((w, 2)), decode(e^0b0010000000000001));
        assert_eq!(Some((w, 2)), decode(e^0b0001000000000010));
        assert_eq!(Some((w, 2)), decode(e^0b0000100000000100));
        assert_eq!(Some((w, 2)), decode(e^0b0000010000001000));
        assert_eq!(Some((w, 2)), decode(e^0b0000001000010000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000100100000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000011000000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000001010000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000010001000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000100000100));
        assert_eq!(Some((w, 2)), decode(e^0b0000001000000010));
        assert_eq!(Some((w, 2)), decode(e^0b0000010000000001));
        assert_eq!(Some((w, 1)), decode(e^0b0000100000000000));
        assert_eq!(Some((w, 1)), decode(e^0b0001000000000000));
        assert_eq!(Some((w, 2)), decode(e^0b0010000000000001));
        assert_eq!(Some((w, 2)), decode(e^0b0100000000000100));
        assert_eq!(Some((w, 2)), decode(e^0b1000000000001000));

        for i in 0..1u16<<8 {
            assert_eq!(decode(encode(i as u8)).unwrap().0, i as u8);
        }
    }
}
<|endoftext|>