<commit_before>use std::env;
use std::fmt;
use std::io;
use std::path::Path;
use std::process::{Command, Output};
use std::str;

use console::strip_ansi_codes;
use failure::{bail, err_msg, Error};
use glob::{glob_with, MatchOptions};
// use serde::de::{Deserialize, Deserializer, Error as DeError};
use if_chain::if_chain;
use serde::de;

use crate::utils::releases::{get_xcode_release_name, infer_gradle_release_name};
use crate::utils::xcode::{InfoPlist, XcodeProjectInfo};

#[cfg(not(windows))]
static APPCENTER_BIN_PATH: &str = "appcenter";
#[cfg(not(windows))]
static APPCENTER_NPM_PATH: &str = "node_modules/.bin/appcenter";

#[cfg(windows)]
static APPCENTER_BIN_PATH: &str = "appcenter.cmd";
#[cfg(windows)]
static APPCENTER_NPM_PATH: &str = "node_modules/.bin/appcenter.cmd";

static APPCENTER_NOT_FOUND: &str = "AppCenter CLI not found

Install with `npm install -g appcenter-cli` and make sure it is on the PATH.";

#[derive(Debug)]
pub struct AppCenterPackage {
    pub label: String,
}

impl<'de> de::Deserialize<'de> for AppCenterPackage {
    fn deserialize<D: de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        struct PackageVisitor;

        impl<'de> de::Visitor<'de> for PackageVisitor {
            type Value = AppCenterPackage;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                formatter.write_str("a deployment history entry")
            }

            fn visit_seq<S: de::SeqAccess<'de>>(
                self,
                mut seq: S,
            ) -> Result<AppCenterPackage, S::Error> {
                // Since we only need the package label, we can deserialize the JSON string very
                // efficiently by only looking at the first element.
                let label = seq
                    .next_element()?
                    .ok_or_else(|| de::Error::custom("missing package label"))?;

                // Drain the sequence, ignoring all other values.
                while seq.next_element::<de::IgnoredAny>()?.is_some() {}

                Ok(AppCenterPackage { label })
            }
        }

        deserializer.deserialize_seq(PackageVisitor)
    }
}

pub fn get_appcenter_error(output: &Output) -> Error {
    let message = str::from_utf8(&output.stdout).unwrap_or("Unknown AppCenter error");

    let stripped = strip_ansi_codes(message);
    let cause = if let Some(rest) = stripped.strip_prefix("Error: ") {
        rest
    } else {
        &stripped
    }
    .to_string();

    err_msg(cause)
}

pub fn get_appcenter_deployment_history(
    app: &str,
    deployment: &str,
) -> Result<Vec<AppCenterPackage>, Error> {
    let appcenter_bin = if Path::new(APPCENTER_NPM_PATH).exists() {
        APPCENTER_NPM_PATH
    } else {
        APPCENTER_BIN_PATH
    };

    let output = Command::new(appcenter_bin)
        .arg("codepush")
        .arg("deployment")
        .arg("history")
        .arg(deployment)
        .arg("--app")
        .arg(app)
        .arg("--output")
        .arg("json")
        .output()
        .map_err(|e| match e.kind() {
            io::ErrorKind::NotFound => APPCENTER_NOT_FOUND.into(),
            _ => Error::from(e).context("Failed to run AppCenter CLI"),
        })?;

    if output.status.success() {
        Ok(serde_json::from_slice(&output.stdout).unwrap_or_else(|_| {
            let err_msg = format!("Command `{} codepush deployment history {} --app {} --output json` failed to produce a valid JSON output.", appcenter_bin, deployment, app);
            panic!("{}", err_msg);
        }))
    } else {
        Err(get_appcenter_error(&output)
            .context("Failed to load AppCenter deployment history")
            .into())
    }
}

pub fn get_appcenter_package(app: &str, deployment: &str) -> Result<AppCenterPackage, Error> {
    let history = get_appcenter_deployment_history(app, deployment)?;
    if let Some(latest) = history.into_iter().last() {
        Ok(latest)
    } else {
        bail!("Could not find deployment {} for {}", deployment, app);
    }
}

pub fn get_react_native_appcenter_release(
    package: &AppCenterPackage,
    platform: &str,
    bundle_id_override: Option<&str>,
    version_name_override: Option<&str>,
    release_name_override: Option<&str>,
) -> Result<String, Error> {
    let bundle_id_ovrr = bundle_id_override.unwrap_or("");
    let version_name_ovrr = version_name_override.unwrap_or("");
    let release_name_ovrr = release_name_override.unwrap_or("");

    if !release_name_ovrr.is_empty() {
        return Ok(release_name_ovrr.to_string());
    }

    if !bundle_id_ovrr.is_empty() && !version_name_ovrr.is_empty() {
        return Ok(format!(
            "{}@{}+codepush:{}",
            bundle_id_ovrr, version_name_ovrr, package.label
        ));
    }

    if platform == "ios" {
        if !cfg!(target_os = "macos") {
            bail!("AppCenter codepush releases for iOS require macOS if no bundle ID is specified");
        }

        let mut opts = MatchOptions::new();
        opts.case_sensitive = false;

        for entry in (glob_with("ios/*.xcodeproj", opts)?).flatten() {
            let pi = XcodeProjectInfo::from_path(&entry)?;
            if let Some(ipl) = InfoPlist::from_project_info(&pi)? {
                if let Some(release_name) = get_xcode_release_name(Some(ipl))? {
                    let vec: Vec<&str> = release_name.split('@').collect();
                    let bundle_id = if bundle_id_ovrr.is_empty() {
                        vec[0]
                    } else {
                        bundle_id_ovrr
                    };
                    let version_name = if version_name_ovrr.is_empty() {
                        vec[1]
                    } else {
                        version_name_ovrr
                    };
                    return Ok(format!(
                        "{}@{}+codepush:{}",
                        bundle_id, version_name, package.label
                    ));
                }
            }
        }

        bail!("Could not find plist");
    } else if platform == "android" {
        if_chain! {
            if let Ok(here) = env::current_dir();
            if let Ok(android_folder) = here.join("android").metadata();
            if android_folder.is_dir();
            then {
                if let Some(release_name) = infer_gradle_release_name(Some(here.join("android")))? {
                    let vec: Vec<&str> = release_name.split('@').collect();
                    let bundle_id = if bundle_id_ovrr.is_empty() { vec[0] } else { bundle_id_ovrr };
                    let version_name = if version_name_ovrr.is_empty() { vec[1] } else { version_name_ovrr };
                    return Ok(format!("{}@{}+codepush:{}", bundle_id, version_name, package.label));
                } else {
                    bail!("Could not parse app id from build.gradle");
                }
            }
        }

        bail!("Could not find AndroidManifest.xml");
    }

    bail!("Unsupported platform '{}'", platform);
}
<commit_msg>ref: Update log message when bundle ID is missing (#1113)<commit_after>use std::env;
use std::fmt;
use std::io;
use std::path::Path;
use std::process::{Command, Output};
use std::str;

use console::strip_ansi_codes;
use failure::{bail, err_msg, Error};
use glob::{glob_with, MatchOptions};
// use serde::de::{Deserialize, Deserializer, Error as DeError};
use if_chain::if_chain;
use serde::de;

use crate::utils::releases::{get_xcode_release_name, infer_gradle_release_name};
use crate::utils::xcode::{InfoPlist, XcodeProjectInfo};

#[cfg(not(windows))]
static APPCENTER_BIN_PATH: &str = "appcenter";
#[cfg(not(windows))]
static APPCENTER_NPM_PATH: &str = "node_modules/.bin/appcenter";

#[cfg(windows)]
static APPCENTER_BIN_PATH: &str = "appcenter.cmd";
#[cfg(windows)]
static APPCENTER_NPM_PATH: &str = "node_modules/.bin/appcenter.cmd";

static APPCENTER_NOT_FOUND: &str = "AppCenter CLI not found

Install with `npm install -g appcenter-cli` and make sure it is on the PATH.";

#[derive(Debug)]
pub struct AppCenterPackage {
    pub label: String,
}

impl<'de> de::Deserialize<'de> for AppCenterPackage {
    fn deserialize<D: de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        struct PackageVisitor;

        impl<'de> de::Visitor<'de> for PackageVisitor {
            type Value = AppCenterPackage;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                formatter.write_str("a deployment history entry")
            }

            fn visit_seq<S: de::SeqAccess<'de>>(
                self,
                mut seq: S,
            ) -> Result<AppCenterPackage, S::Error> {
                // Since we only need the package label, we can deserialize the JSON string very
                // efficiently by only looking at the first element.
                let label = seq
                    .next_element()?
                    .ok_or_else(|| de::Error::custom("missing package label"))?;

                // Drain the sequence, ignoring all other values.
                while seq.next_element::<de::IgnoredAny>()?.is_some() {}

                Ok(AppCenterPackage { label })
            }
        }

        deserializer.deserialize_seq(PackageVisitor)
    }
}

pub fn get_appcenter_error(output: &Output) -> Error {
    let message = str::from_utf8(&output.stdout).unwrap_or("Unknown AppCenter error");

    let stripped = strip_ansi_codes(message);
    let cause = if let Some(rest) = stripped.strip_prefix("Error: ") {
        rest
    } else {
        &stripped
    }
    .to_string();

    err_msg(cause)
}

pub fn get_appcenter_deployment_history(
    app: &str,
    deployment: &str,
) -> Result<Vec<AppCenterPackage>, Error> {
    let appcenter_bin = if Path::new(APPCENTER_NPM_PATH).exists() {
        APPCENTER_NPM_PATH
    } else {
        APPCENTER_BIN_PATH
    };

    let output = Command::new(appcenter_bin)
        .arg("codepush")
        .arg("deployment")
        .arg("history")
        .arg(deployment)
        .arg("--app")
        .arg(app)
        .arg("--output")
        .arg("json")
        .output()
        .map_err(|e| match e.kind() {
            io::ErrorKind::NotFound => APPCENTER_NOT_FOUND.into(),
            _ => Error::from(e).context("Failed to run AppCenter CLI"),
        })?;

    if output.status.success() {
        Ok(serde_json::from_slice(&output.stdout).unwrap_or_else(|_| {
            let err_msg = format!("Command `{} codepush deployment history {} --app {} --output json` failed to produce a valid JSON output.", appcenter_bin, deployment, app);
            panic!("{}", err_msg);
        }))
    } else {
        Err(get_appcenter_error(&output)
            .context("Failed to load AppCenter deployment history")
            .into())
    }
}

pub fn get_appcenter_package(app: &str, deployment: &str) -> Result<AppCenterPackage, Error> {
    let history = get_appcenter_deployment_history(app, deployment)?;
    if let Some(latest) = history.into_iter().last() {
        Ok(latest)
    } else {
        bail!("Could not find deployment {} for {}", deployment, app);
    }
}

pub fn get_react_native_appcenter_release(
    package: &AppCenterPackage,
    platform: &str,
    bundle_id_override: Option<&str>,
    version_name_override: Option<&str>,
    release_name_override: Option<&str>,
) -> Result<String, Error> {
    let bundle_id_ovrr = bundle_id_override.unwrap_or("");
    let version_name_ovrr = version_name_override.unwrap_or("");
    let release_name_ovrr = release_name_override.unwrap_or("");

    if !release_name_ovrr.is_empty() {
        return Ok(release_name_ovrr.to_string());
    }

    if !bundle_id_ovrr.is_empty() && !version_name_ovrr.is_empty() {
        return Ok(format!(
            "{}@{}+codepush:{}",
            bundle_id_ovrr, version_name_ovrr, package.label
        ));
    }

    if platform == "ios" {
        if !cfg!(target_os = "macos") {
            bail!("AppCenter codepush releases for iOS require macOS if no bundle ID and version name are specified");
        }

        let mut opts = MatchOptions::new();
        opts.case_sensitive = false;

        for entry in (glob_with("ios/*.xcodeproj", opts)?).flatten() {
            let pi = XcodeProjectInfo::from_path(&entry)?;
            if let Some(ipl) = InfoPlist::from_project_info(&pi)? {
                if let Some(release_name) = get_xcode_release_name(Some(ipl))? {
                    let vec: Vec<&str> = release_name.split('@').collect();
                    let bundle_id = if bundle_id_ovrr.is_empty() {
                        vec[0]
                    } else {
                        bundle_id_ovrr
                    };
                    let version_name = if version_name_ovrr.is_empty() {
                        vec[1]
                    } else {
                        version_name_ovrr
                    };
                    return Ok(format!(
                        "{}@{}+codepush:{}",
                        bundle_id, version_name, package.label
                    ));
                }
            }
        }

        bail!("Could not find plist");
    } else if platform == "android" {
        if_chain! {
            if let Ok(here) = env::current_dir();
            if let Ok(android_folder) = here.join("android").metadata();
            if android_folder.is_dir();
            then {
                if let Some(release_name) = infer_gradle_release_name(Some(here.join("android")))? {
                    let vec: Vec<&str> = release_name.split('@').collect();
                    let bundle_id = if bundle_id_ovrr.is_empty() { vec[0] } else { bundle_id_ovrr };
                    let version_name = if version_name_ovrr.is_empty() { vec[1] } else { version_name_ovrr };
                    return Ok(format!("{}@{}+codepush:{}", bundle_id, version_name, package.label));
                } else {
                    bail!("Could not parse app id from build.gradle");
                }
            }
        }

        bail!("Could not find AndroidManifest.xml");
    }

    bail!("Unsupported platform '{}'", platform);
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/dungeon-game/
pub fn calculate_minimum_hp(dungeon: Vec<Vec<i32>>) -> i32 {
    fn f(dungeon: &Vec<Vec<i32>>, row: i32, col: i32, sum: i32, health: i32) -> i32 {
        let max_rows = dungeon.len() as i32;
        let max_cols = if max_rows > 0 { dungeon[0].len() } else { 0 } as i32;
        let value = &dungeon[row as usize][col as usize];
        let health = if sum + value <= 0 {
            (sum + value).abs() + 1
        } else {
            health
        };
        if row == max_rows - 1 && col == max_cols - 1 {
            return health;
        }
        let mut min = i32::MAX;
        if col + 1 < max_cols {
            let right = f(dungeon, row, col + 1, sum + value, health);
            min = min.min(right);
        }
        if row + 1 < max_rows {
            let down = f(dungeon, row + 1, col, sum + value, health);
            min = min.min(down);
        }
        min
    }

    f(&dungeon, 0, 0, 0, 1)
}

fn main() {
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![-2, -3, 3], vec![-5, -10, 1], vec![10, 30, -5]])
    ); // 7
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![2, 3, 3], vec![5, 10, 1], vec![10, 30, 5]])
    ); // 1
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![2, -3, 3], vec![-5, -10, 1], vec![10, 30, -5]])
    ); // 3
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![2, 3, 3], vec![-5, -10, 1], vec![10, 30, 5]])
    ); // 1
    println!("{}", calculate_minimum_hp(vec![vec![0]])); // 1
}
<commit_msg>Solve problem 174<commit_after>// https://leetcode.com/problems/dungeon-game/
pub fn calculate_minimum_hp(dungeon: Vec<Vec<i32>>) -> i32 {
    fn f(dungeon: &Vec<Vec<i32>>, row: i32, col: i32, memo: &mut Vec<Vec<i32>>) -> i32 {
        let max_rows = dungeon.len() as i32;
        let max_cols = if max_rows > 0 { dungeon[0].len() } else { 0 } as i32;
        if row == max_rows || col == max_cols {
            return i32::MAX;
        }
        if memo[row as usize][col as usize] != -1 {
            return memo[row as usize][col as usize];
        }
        let value = &dungeon[row as usize][col as usize];
        if row == max_rows - 1 && col == max_cols - 1 {
            return if *value <= 0 { -value + 1 } else { 1 };
        }
        let right = f(dungeon, row, col + 1, memo);
        let down = f(dungeon, row + 1, col, memo);
        let min = right.min(down) - value;
        let min = if min <= 0 { 1 } else { min };
        memo[row as usize][col as usize] = min;
        min
    }

    let max_rows = dungeon.len() as i32;
    let max_cols = if max_rows > 0 { dungeon[0].len() } else { 0 } as i32;
    f(
        &dungeon,
        0,
        0,
        &mut vec![vec![-1; max_cols as usize]; max_rows as usize],
    )
}

fn main() {
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![-2, -3, 3], vec![-5, -10, 1], vec![10, 30, -5]])
    ); // 7
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![2, 3, 3], vec![5, 10, 1], vec![10, 30, 5]])
    ); // 1
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![2, -3, 3], vec![-5, -10, 1], vec![10, 30, -5]])
    ); // 3
    println!(
        "{}",
        calculate_minimum_hp(vec![vec![2, 3, 3], vec![-5, -10, 1], vec![10, 30, 5]])
    ); // 1
    println!("{}", calculate_minimum_hp(vec![vec![0]])); // 1
}
<|endoftext|>


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

use std::fmt::Display;
use std::cell::RefCell;

#[derive(Default)]
pub struct Ctxt {
    errors: RefCell<Option<Vec<String>>>,
}

impl Ctxt {
    pub fn new() -> Self {
        Ctxt {
            errors: RefCell::new(Some(Vec::new())),
        }
    }

    pub fn error<T: Display>(&self, msg: T) {
        self.errors
            .borrow_mut()
            .as_mut()
            .unwrap()
            .push(msg.to_string());
    }

    pub fn check(self) -> Result<(), String> {
        let mut errors = self.errors.borrow_mut().take().unwrap();
        match errors.len() {
            0 => Ok(()),
            1 => Err(errors.pop().unwrap()),
            n => {
                let mut msg = format!("{} errors:", n);
                for err in errors {
                    msg.push_str("\n\t# ");
                    msg.push_str(&err);
                }
                Err(msg)
            }
        }
    }
}

impl Drop for Ctxt {
    fn drop(&mut self) {
        if self.errors.borrow().is_some() {
            panic!("forgot to check for errors");
        }
    }
}
<commit_msg>Drop impl should only panic if not already panicking<commit_after>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt::Display;
use std::cell::RefCell;
use std::thread;

#[derive(Default)]
pub struct Ctxt {
    errors: RefCell<Option<Vec<String>>>,
}

impl Ctxt {
    pub fn new() -> Self {
        Ctxt {
            errors: RefCell::new(Some(Vec::new())),
        }
    }

    pub fn error<T: Display>(&self, msg: T) {
        self.errors
            .borrow_mut()
            .as_mut()
            .unwrap()
            .push(msg.to_string());
    }

    pub fn check(self) -> Result<(), String> {
        let mut errors = self.errors.borrow_mut().take().unwrap();
        match errors.len() {
            0 => Ok(()),
            1 => Err(errors.pop().unwrap()),
            n => {
                let mut msg = format!("{} errors:", n);
                for err in errors {
                    msg.push_str("\n\t# ");
                    msg.push_str(&err);
                }
                Err(msg)
            }
        }
    }
}

impl Drop for Ctxt {
    fn drop(&mut self) {
        if !thread::panicking() && self.errors.borrow().is_some() {
            panic!("forgot to check for errors");
        }
    }
}
<|endoftext|>


<commit_before>use screen::*;
use piston_window;
use conrod::{self, Widget, Frameable, Positionable};
use conrod::color::Colorable;

pub struct MainMenuScreen {
    ui: conrod::Ui<piston_window::Glyphs>,
}

impl MainMenuScreen {
    pub fn new(window: &piston_window::PistonWindow, context: &mut Context) -> MainMenuScreen {
        MainMenuScreen { ui: create_ui(&window, &context.assets_path) }
    }
}

impl Screen for MainMenuScreen {
    fn on_input(&mut self,
                input: &piston_window::Input,
                window: &piston_window::PistonWindow,
                context: &mut Context)
                -> InputResults {
        use piston_window::{Input, Button, MouseButton};

        let mut result = Vec::new();

        match input {
            &Input::Press(Button::Mouse(MouseButton::Left)) => {
                result.push(InputResult::PopScreen);
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new(&window, context))));
            }
            _ => {}
        }

        result
    }

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

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
        self.ui.set_widgets(|ui| {
            conrod::Canvas::new()
                .frame(200.)
                .pad(30.0)
                .color(conrod::color::rgb(0.2, 0.35, 0.45))
                .scroll_kids()
                .set(CANVAS, ui);

            conrod::Text::new("Widget Demonstration")
                .top_left_with_margins_on(CANVAS, 0.0, 350.0)
                .font_size(32)
                .color(conrod::color::rgb(0.2, 0.35, 0.45).plain_contrast())
                .set(TITLE, ui);

            // TODO: Button.
        });
    }
}

widget_ids! {
    CANVAS,
    TITLE,
}

fn create_ui(window: &piston_window::PistonWindow,
             assets_path: &::std::path::Path)
             -> conrod::Ui<piston_window::Glyphs> {
    let font_path = assets_path.join("NotoSans-Regular.ttf");
    let theme = conrod::Theme::default();
    let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.borrow().clone());
    conrod::Ui::new(glyph_cache.unwrap(), theme)
}
<commit_msg>Additional UI ids<commit_after>use screen::*;
use piston_window;
use conrod::{self, Widget, Frameable, Positionable};
use conrod::color::Colorable;

pub struct MainMenuScreen {
    ui: conrod::Ui<piston_window::Glyphs>,
}

impl MainMenuScreen {
    pub fn new(window: &piston_window::PistonWindow, context: &mut Context) -> MainMenuScreen {
        MainMenuScreen { ui: create_ui(&window, &context.assets_path) }
    }
}

impl Screen for MainMenuScreen {
    fn on_input(&mut self,
                input: &piston_window::Input,
                window: &piston_window::PistonWindow,
                context: &mut Context)
                -> InputResults {
        use piston_window::{Input, Button, MouseButton};

        let mut result = Vec::new();

        match input {
            &Input::Press(Button::Mouse(MouseButton::Left)) => {
                result.push(InputResult::PopScreen);
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new(&window, context))));
            }
            _ => {}
        }

        result
    }

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

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
        self.ui.set_widgets(|ui| {
            conrod::Canvas::new()
                .frame(200.)
                .pad(30.0)
                .color(conrod::color::rgb(0.2, 0.35, 0.45))
                .scroll_kids()
                .set(CANVAS, ui);

            conrod::Text::new("Main menu")
                .top_left_with_margins_on(CANVAS, 0.0, 350.0)
                .font_size(32)
                .color(conrod::color::rgb(0.2, 0.35, 0.45).plain_contrast())
                .set(TITLE, ui);

            // TODO: Button.
        });
    }
}

widget_ids! {
    CANVAS,
    TITLE,
    NEW_GAME_BUTTON,
    EXIT_BUTTON,
}

fn create_ui(window: &piston_window::PistonWindow,
             assets_path: &::std::path::Path)
             -> conrod::Ui<piston_window::Glyphs> {
    let font_path = assets_path.join("NotoSans-Regular.ttf");
    let theme = conrod::Theme::default();
    let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.borrow().clone());
    conrod::Ui::new(glyph_cache.unwrap(), theme)
}
<|endoftext|>


<commit_before>#![feature(vec_resize)]

use std::iter::repeat;
use std::collections::VecDeque;
use std::collections::BinaryHeap;
use std::cmp::Ordering;

fn max(a: u32, b: u32) -> u32 { if a > b { a } else { b } }

#[derive(Clone)]
struct Edge {
    vertex: u32,
    weight: f32,
}

impl Edge {
    pub fn new(vertex_: u32, weight_: f32) -> Edge {
        Edge{vertex: vertex_, weight: weight_,}
    }
}

impl Ord for Edge {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

impl Eq for Edge {}

impl PartialOrd for Edge {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        (self.weight, self.vertex).partial_cmp(&(other.weight, other.vertex))
    }
}

impl PartialEq for Edge {
    fn eq(&self, other: &Self) -> bool {
        (self.weight, &self.vertex) == (other.weight, &other.vertex)
    }
}

struct Graph {
    nodes: Vec<Vec<Edge>>,
}

impl Graph {
    pub fn new() -> Graph { Graph{nodes: Vec::new(),} }

    pub fn add_edge(&mut self, src: u32, dst: u32, weight: f32) {
        let len = self.nodes.len();

        if (max(src, dst)) > len as u32 {
            let new_len = (max(src, dst) + 1) as usize;
            self.nodes.extend(repeat(Vec::new()).take(new_len - len))
        }
        self.nodes[src as usize].push(Edge::new(dst, weight));
    }

    pub fn bfs(&self, src: u32) {
        let mut queue: VecDeque<u32> = VecDeque::new();
        let len = self.nodes.len();
        let mut visited = vec!(false ; len);

        queue.push_front(src);

        while let Some(current) = queue.pop_back() {
            if !visited[current as usize] {
                println!("current: {}" , current);
                visited[current as usize] = true;
            } else { continue ; }

            for n in &self.nodes[current as usize] {
                let neighbor: u32 = n.vertex;
                queue.push_front(neighbor);
            }
        }
    }

    pub fn dfs(&self, src: u32) {
        let mut stack: Vec<u32> = Vec::new();
        let len = self.nodes.len() as usize;
        let mut visited = vec!(false ; len);

        stack.push(src);

        while let Some(current) = stack.pop() {
            if !visited[current as usize] {
                println!("current: {}" , current);
                visited[current as usize] = true;
            } else { continue ; }

            for n in &self.nodes[current as usize] {
                let neighbor: u32 = n.vertex;
                stack.push(neighbor);
            }
        }
    }

    pub fn dijkstra(&self, src: u32, dst: u32) {
      let mut dist: Vec<f32> = Vec::new();
      let mut prev: Vec<u32> = Vec::new();
      let mut q = BinaryHeap::new();
      const MAX_WEIGHT: f32 = std::f32::MAX;

      // init dist, prev table
      // would only work in rust nightly
      dist.resize(self.nodes.len(), MAX_WEIGHT);
      prev.resize(self.nodes.len(), 0);

      // We're at `start`, with a zero cost
      dist[src as usize] = 0.0;
      q.push(Edge::new(src, dist[src as usize]));

      while let Some(u) = q.pop() {
        // loop for all edges connected to
        for v in self.nodes[u.vertex as usize].iter() {

          let alt: f32 = dist[u.vertex as usize] + v.weight; // accumulate shortest dist from source

          // The variable alt is the length of the path from the root node to the neighbor node v
          // if it were to go through u. If this path is shorter than the current shortest path
          // recorded for v, that current path is replaced with this alt path.
          if alt < dist[v.vertex as usize] {
            dist[v.vertex as usize] = alt; // keep the shortest dist from src to v
            prev[v.vertex as usize] = u.vertex;

            q.push(Edge::new(v.vertex, dist[v.vertex as usize])); // Add unvisited v into the Q to be processed
          }
        }
      }

      let mut shortest_path: Vec<u32> = Vec::new();
      let mut curr: u32 = dst;

      shortest_path.push(curr);

      while curr != src {
        curr = prev[curr as usize];
        shortest_path.push(curr);
      }

      shortest_path.reverse();

      for v in shortest_path.iter() {
        println!("{}", v);
      }
    }
}

fn main() {
    let mut g1 = Graph::new();
    g1.add_edge(0, 1, 1.0);
    g1.add_edge(0, 2, 4.0);
    g1.add_edge(1, 0, 1.0);
    g1.add_edge(1, 2, 2.0);
    g1.add_edge(1, 3, 6.0);
    g1.add_edge(2, 0, 4.0);
    g1.add_edge(2, 1, 2.0);
    g1.add_edge(2, 3, 3.0);
    g1.add_edge(3, 1, 6.0);
    g1.add_edge(3, 2, 3.0);

    g1.bfs(3);

    println!("");

    g1.dfs(3);

    println!("");

    g1.dijkstra(0, 3);
}<commit_msg>small changes<commit_after>#![feature(vec_resize)]

use std::iter::repeat;
use std::collections::VecDeque;
use std::collections::BinaryHeap;
use std::cmp::Ordering;

fn max(a: u32, b: u32) -> u32 { if a > b { a } else { b } }

#[derive(Clone)]
struct Edge {
    vertex: u32,
    weight: f32,
}

impl Edge {
    pub fn new(vertex_: u32, weight_: f32) -> Edge {
        Edge{vertex: vertex_, weight: weight_,}
    }
}

impl Ord for Edge {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

impl Eq for Edge {}

impl PartialOrd for Edge {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        (self.weight, self.vertex).partial_cmp(&(other.weight, other.vertex))
    }
}

impl PartialEq for Edge {
    fn eq(&self, other: &Self) -> bool {
        (self.weight, &self.vertex) == (other.weight, &other.vertex)
    }
}

struct Graph {
    nodes: Vec<Vec<Edge>>,
}

impl Graph {
    pub fn new() -> Graph { Graph{nodes: Vec::new(),} }

    pub fn add_edge(&mut self, src: u32, dst: u32, weight: f32) {
        let len = self.nodes.len();

        if (max(src, dst)) > len as u32 {
            let new_len = (max(src, dst) + 1) as usize;
            self.nodes.extend(repeat(Vec::new()).take(new_len - len))
        }
        self.nodes[src as usize].push(Edge::new(dst, weight));
    }

    pub fn bfs(&self, src: u32) {
        let mut queue: VecDeque<u32> = VecDeque::new();
        let len = self.nodes.len();
        let mut visited = vec!(false ; len);

        queue.push_front(src);

        while let Some(current) = queue.pop_back() {
            if !visited[current as usize] {
                println!("current: {}" , current);
                visited[current as usize] = true;
            } else { continue ; }

            for n in &self.nodes[current as usize] {
                let neighbor: u32 = n.vertex;
                queue.push_front(neighbor);
            }
        }
    }

    pub fn dfs(&self, src: u32) {
        let mut stack: Vec<u32> = Vec::new();
        let len = self.nodes.len() as usize;
        let mut visited = vec!(false ; len);

        stack.push(src);

        while let Some(current) = stack.pop() {
            if !visited[current as usize] {
                println!("current: {}" , current);
                visited[current as usize] = true;
            } else { continue ; }

            for n in &self.nodes[current as usize] {
                let neighbor: u32 = n.vertex;
                stack.push(neighbor);
            }
        }
    }

    pub fn dijkstra(&self, src: u32, dst: u32) {
      let mut dist: Vec<f32> = Vec::new();
      let mut prev: Vec<u32> = Vec::new();
      let mut q = BinaryHeap::new();
      const MAX_WEIGHT: f32 = std::f32::MAX;

      // init dist, prev table
      // would only work in rust nightly
      dist.resize(self.nodes.len(), MAX_WEIGHT);
      prev.resize(self.nodes.len(), 0);

      // We're at `start`, with a zero cost
      dist[src as usize] = 0.0;
      q.push(Edge::new(src, dist[src as usize]));

      while let Some(u) = q.pop() {
        // loop for all edges connected to
        for v in self.nodes[u.vertex as usize].iter() {

          let alt: f32 = dist[u.vertex as usize] + v.weight; // accumulate shortest dist from source

          // The variable alt is the length of the path from the root node to the neighbor node v
          // if it were to go through u. If this path is shorter than the current shortest path
          // recorded for v, that current path is replaced with this alt path.
          if alt < dist[v.vertex as usize] {
            dist[v.vertex as usize] = alt; // keep the shortest dist from src to v
            prev[v.vertex as usize] = u.vertex;

            q.push(Edge::new(v.vertex, dist[v.vertex as usize])); // Add unvisited v into the Q to be processed
          }
        }
      }

      let mut shortest_path: Vec<u32> = Vec::new();
      let mut curr: u32 = dst;

      shortest_path.push(curr);

      while curr != src {
        curr = prev[curr as usize];
        shortest_path.push(curr);
      }

      shortest_path.reverse();

      for v in shortest_path.iter() {
        println!("current: {}", v);
      }
    }
}

fn main() {
    let mut g1 = Graph::new();
    g1.add_edge(0, 1, 1.0);
    g1.add_edge(0, 2, 4.0);
    g1.add_edge(1, 0, 1.0);
    g1.add_edge(1, 2, 2.0);
    g1.add_edge(1, 3, 6.0);
    g1.add_edge(2, 0, 4.0);
    g1.add_edge(2, 1, 2.0);
    g1.add_edge(2, 3, 3.0);
    g1.add_edge(3, 1, 6.0);
    g1.add_edge(3, 2, 3.0);

    println!("bfs");
    g1.bfs(0);

    println!("");

    println!("dfs");
    g1.dfs(0);

    println!("");

    println!("dijkstra");
    g1.dijkstra(0, 3);
}<|endoftext|>


<commit_before>//! Implements `Multipv`.

use std::cmp::{min, max};
use std::time::Duration;
use std::sync::{Arc, RwLock};
use std::sync::mpsc::TryRecvError;
use uci::{SetOption, OptionDescription};
use moves::Move;
use value::*;
use depth::*;
use hash_table::*;
use evaluator::Evaluator;
use search_node::SearchNode;
use search_executor::{SearchParams, SearchReport, SearchExecutor};
use time_manager::RemainingTime;
use super::{bogus_params, contains_dups};
use super::aspiration::Aspiration;

/// Executes mulit-PV searches with aspiration windows, complying with
/// `searchmoves`.
///
/// The final progress report contains the `searchmoves` vector sorted
/// by descending move strength.
pub struct Multipv<T: SearchExecutor> {
    tt: Arc<T::HashTable>,
    params: SearchParams<T::SearchNode>,
    search_is_terminated: bool,
    previously_searched_nodes: u64,

    // The real work will be handed over to `searcher`.
    searcher: Aspiration<T>,

    // The number of best lines of play that should be calculated.
    variation_count: usize,

    // Whether all legal moves in the root position are considered.
    all_moves_are_considered: bool,

    // The index in `self.params.searchmoves` of the currently
    // considered move.
    current_move_index: usize,

    // The values for the corresponding moves in `self.params.searchmoves`.
    values: Vec<Value>,
}

impl<T: SearchExecutor> SearchExecutor for Multipv<T> {
    type HashTable = T::HashTable;

    type SearchNode = T::SearchNode;

    type ReportData = Vec<Move>;

    fn new(tt: Arc<Self::HashTable>) -> Multipv<T> {
        Multipv {
            tt: tt.clone(),
            params: bogus_params(),
            search_is_terminated: false,
            previously_searched_nodes: 0,
            searcher: Aspiration::new(tt),
            variation_count: 1,
            all_moves_are_considered: true,
            current_move_index: 0,
            values: vec![VALUE_MIN],
        }
    }

    fn start_search(&mut self, params: SearchParams<T::SearchNode>, _: Option<&RemainingTime>) {
        debug_assert!(params.depth > 0);
        debug_assert!(params.depth <= DEPTH_MAX);
        debug_assert!(params.lower_bound >= VALUE_MIN);
        debug_assert!(params.upper_bound <= VALUE_MAX);
        debug_assert!(params.lower_bound < params.upper_bound);
        debug_assert!(!contains_dups(&params.searchmoves));

        let n = params.searchmoves.len();
        self.all_moves_are_considered = n == params.position.legal_moves().len();
        self.params = params;
        self.search_is_terminated = false;
        self.previously_searched_nodes = 0;
        self.variation_count = min(n, *VARIATION_COUNT.read().unwrap());
        if n == 0 || self.variation_count == 1 && self.all_moves_are_considered {
            // A plain aspiration search.
            //
            // A search is not a genuine multi-PV search if all legal
            // moves in the root position are being considered, and
            // the number of best lines of play that should be
            // calculated is one or zero. In those cases we fall-back
            // to a plain aspiration search.
            debug_assert!(self.variation_count <= 1);
            self.searcher.lmr_mode = false;
            self.searcher.start_search(self.params.clone(), None);
        } else {
            // A genuine multi-PV search.
            debug_assert!(self.variation_count >= 1);
            self.searcher.lmr_mode = true;
            self.current_move_index = 0;
            self.values = vec![VALUE_MIN; n];
            self.search_current_move();
        }
    }

    fn try_recv_report(&mut self) -> Result<SearchReport<Self::ReportData>, TryRecvError> {
        if self.runs_genuine_multipv_search() {
            let SearchReport { searched_nodes, value, done, .. } = try!(self.searcher
                                                                            .try_recv_report());
            let mut report = SearchReport {
                search_id: self.params.search_id,
                searched_nodes: self.previously_searched_nodes + searched_nodes,
                depth: 0,
                value: VALUE_UNKNOWN,
                data: vec![],
                done: done,
            };
            if done && !self.search_is_terminated {
                self.previously_searched_nodes = report.searched_nodes;
                self.params.position.undo_last_move();
                self.advance_current_move(-value);
                if self.search_current_move() {
                    report.done = false;
                } else {
                    report.depth = self.params.depth;
                    report.value = self.values[0];
                    report.data = self.params.searchmoves.clone();
                }
            }
            Ok(report)
        } else {
            self.searcher.try_recv_report()
        }
    }

    fn wait_report(&self, duration: Duration) {
        self.searcher.wait_report(duration);
    }

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

impl<T: SearchExecutor> SetOption for Multipv<T> {
    fn options() -> Vec<(String, OptionDescription)> {
        let mut options = vec![
            ("MultiPV".to_string(), OptionDescription::Spin { min: 1, max: 500, default: 1 }),
        ];
        options.extend(Aspiration::<T>::options());
        options
    }

    fn set_option(name: &str, value: &str) {
        if name == "MultiPV" {
            *VARIATION_COUNT.write().unwrap() = max(value.parse::<usize>().unwrap_or(0), 1);
        }
        Aspiration::<T>::set_option(name, value)
    }
}

impl<T: SearchExecutor> Multipv<T> {
    /// Returns the best lines of play so far.
    pub fn extract_variations(&mut self) -> Vec<Variation> {
        let mut variations = vec![];
        if self.runs_genuine_multipv_search() {
            for m in self.params.searchmoves.iter().take(self.variation_count) {
                let p = &mut self.params.position;
                assert!(p.do_move(*m));
                let mut v = self.tt.extract_pv(p);
                p.undo_last_move();
                v.moves.insert(0, *m);
                v.value = -v.value;
                v.bound = match v.bound {
                    BOUND_LOWER => BOUND_UPPER,
                    BOUND_UPPER => BOUND_LOWER,
                    x => x,
                };
                variations.push(v);
            }
        } else if self.variation_count != 0 {
            debug_assert_eq!(self.variation_count, 1);
            variations.push(self.tt.extract_pv(&self.params.position));
        }
        variations
    }

    fn search_current_move(&mut self) -> bool {
        if self.current_move_index < self.params.searchmoves.len() {
            let alpha = self.values[self.variation_count - 1];
            if alpha < self.params.upper_bound {
                let m = self.params.searchmoves[self.current_move_index];
                assert!(self.params.position.do_move(m));
                self.previously_searched_nodes += 1;
                self.searcher.start_search(SearchParams {
                                               search_id: 0,
                                               depth: self.params.depth - 1,
                                               lower_bound: -self.params.upper_bound,
                                               upper_bound: -max(alpha, self.params.lower_bound),
                                               searchmoves: self.params.position.legal_moves(),
                                               ..self.params.clone()
                                           },
                                           None);
                return true;
            }
        }
        self.write_reslut_to_tt();
        false
    }

    fn write_reslut_to_tt(&self) {
        if self.all_moves_are_considered {
            let value = self.values[0];
            let bound = match value {
                v if v <= self.params.lower_bound => BOUND_UPPER,
                v if v >= self.params.upper_bound => BOUND_LOWER,
                _ => BOUND_EXACT,
            };
            let best_move = self.params.searchmoves[0];
            let p = &self.params.position;
            self.tt.store(p.hash(), <T::HashTable as HashTable>::Entry::with_static_eval(
                value, bound, self.params.depth, best_move.digest(), p.evaluator().evaluate(p.board())));
        }
    }

    fn advance_current_move(&mut self, v: Value) {
        debug_assert!(v >= self.values[self.current_move_index]);
        let mut i = self.current_move_index;
        self.current_move_index += 1;

        // Update `self.values` making sure that it remains sorted.
        self.values[i] = v;
        while i > 0 && v > self.values[i - 1] {
            self.values.swap(i, i - 1);
            self.params.searchmoves.swap(i, i - 1);
            i -= 1;
        }
    }

    #[inline]
    fn runs_genuine_multipv_search(&self) -> bool {
        self.searcher.lmr_mode
    }
}

lazy_static! {
    static ref VARIATION_COUNT: RwLock<usize> = RwLock::new(1);
}
<commit_msg>fix wrong comment<commit_after>//! Implements `Multipv`.

use std::cmp::{min, max};
use std::time::Duration;
use std::sync::{Arc, RwLock};
use std::sync::mpsc::TryRecvError;
use uci::{SetOption, OptionDescription};
use moves::Move;
use value::*;
use depth::*;
use hash_table::*;
use evaluator::Evaluator;
use search_node::SearchNode;
use search_executor::{SearchParams, SearchReport, SearchExecutor};
use time_manager::RemainingTime;
use super::{bogus_params, contains_dups};
use super::aspiration::Aspiration;

/// Executes mulit-PV searches with aspiration windows, complying with
/// `searchmoves`.
///
/// The auxiliary data field of searches' progress reports will
/// contain either an empty vector of moves, or the `searchmoves`
/// vector sorted by descending move strength. This allows the
/// iterative deepening routine to improve `searchmoves`' order on
/// each iteration.
pub struct Multipv<T: SearchExecutor> {
    tt: Arc<T::HashTable>,
    params: SearchParams<T::SearchNode>,
    search_is_terminated: bool,
    previously_searched_nodes: u64,

    // The real work will be handed over to `searcher`.
    searcher: Aspiration<T>,

    // The number of best lines of play that should be calculated.
    variation_count: usize,

    // Whether all legal moves in the root position are considered.
    all_moves_are_considered: bool,

    // The index in `self.params.searchmoves` of the currently
    // considered move.
    current_move_index: usize,

    // The values for the corresponding moves in `self.params.searchmoves`.
    values: Vec<Value>,
}

impl<T: SearchExecutor> SearchExecutor for Multipv<T> {
    type HashTable = T::HashTable;

    type SearchNode = T::SearchNode;

    type ReportData = Vec<Move>;

    fn new(tt: Arc<Self::HashTable>) -> Multipv<T> {
        Multipv {
            tt: tt.clone(),
            params: bogus_params(),
            search_is_terminated: false,
            previously_searched_nodes: 0,
            searcher: Aspiration::new(tt),
            variation_count: 1,
            all_moves_are_considered: true,
            current_move_index: 0,
            values: vec![VALUE_MIN],
        }
    }

    fn start_search(&mut self, params: SearchParams<T::SearchNode>, _: Option<&RemainingTime>) {
        debug_assert!(params.depth > 0);
        debug_assert!(params.depth <= DEPTH_MAX);
        debug_assert!(params.lower_bound >= VALUE_MIN);
        debug_assert!(params.upper_bound <= VALUE_MAX);
        debug_assert!(params.lower_bound < params.upper_bound);
        debug_assert!(!contains_dups(&params.searchmoves));

        let n = params.searchmoves.len();
        self.all_moves_are_considered = n == params.position.legal_moves().len();
        self.params = params;
        self.search_is_terminated = false;
        self.previously_searched_nodes = 0;
        self.variation_count = min(n, *VARIATION_COUNT.read().unwrap());
        if n == 0 || self.variation_count == 1 && self.all_moves_are_considered {
            // A plain aspiration search.
            //
            // A search is not a genuine multi-PV search if all legal
            // moves in the root position are being considered, and
            // the number of best lines of play that should be
            // calculated is one or zero. In those cases we fall-back
            // to a plain aspiration search.
            debug_assert!(self.variation_count <= 1);
            self.searcher.lmr_mode = false;
            self.searcher.start_search(self.params.clone(), None);
        } else {
            // A genuine multi-PV search.
            debug_assert!(self.variation_count >= 1);
            self.searcher.lmr_mode = true;
            self.current_move_index = 0;
            self.values = vec![VALUE_MIN; n];
            self.search_current_move();
        }
    }

    fn try_recv_report(&mut self) -> Result<SearchReport<Self::ReportData>, TryRecvError> {
        if self.runs_genuine_multipv_search() {
            let SearchReport { searched_nodes, value, done, .. } = try!(self.searcher
                                                                            .try_recv_report());
            let mut report = SearchReport {
                search_id: self.params.search_id,
                searched_nodes: self.previously_searched_nodes + searched_nodes,
                depth: 0,
                value: VALUE_UNKNOWN,
                data: vec![],
                done: done,
            };
            if done && !self.search_is_terminated {
                self.previously_searched_nodes = report.searched_nodes;
                self.params.position.undo_last_move();
                self.advance_current_move(-value);
                if self.search_current_move() {
                    report.done = false;
                } else {
                    report.depth = self.params.depth;
                    report.value = self.values[0];
                    report.data = self.params.searchmoves.clone();
                }
            }
            Ok(report)
        } else {
            self.searcher.try_recv_report()
        }
    }

    fn wait_report(&self, duration: Duration) {
        self.searcher.wait_report(duration);
    }

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

impl<T: SearchExecutor> SetOption for Multipv<T> {
    fn options() -> Vec<(String, OptionDescription)> {
        let mut options = vec![
            ("MultiPV".to_string(), OptionDescription::Spin { min: 1, max: 500, default: 1 }),
        ];
        options.extend(Aspiration::<T>::options());
        options
    }

    fn set_option(name: &str, value: &str) {
        if name == "MultiPV" {
            *VARIATION_COUNT.write().unwrap() = max(value.parse::<usize>().unwrap_or(0), 1);
        }
        Aspiration::<T>::set_option(name, value)
    }
}

impl<T: SearchExecutor> Multipv<T> {
    /// Returns the best lines of play so far.
    pub fn extract_variations(&mut self) -> Vec<Variation> {
        let mut variations = vec![];
        if self.runs_genuine_multipv_search() {
            for m in self.params.searchmoves.iter().take(self.variation_count) {
                let p = &mut self.params.position;
                assert!(p.do_move(*m));
                let mut v = self.tt.extract_pv(p);
                p.undo_last_move();
                v.moves.insert(0, *m);
                v.value = -v.value;
                v.bound = match v.bound {
                    BOUND_LOWER => BOUND_UPPER,
                    BOUND_UPPER => BOUND_LOWER,
                    x => x,
                };
                variations.push(v);
            }
        } else if self.variation_count != 0 {
            debug_assert_eq!(self.variation_count, 1);
            variations.push(self.tt.extract_pv(&self.params.position));
        }
        variations
    }

    fn search_current_move(&mut self) -> bool {
        if self.current_move_index < self.params.searchmoves.len() {
            let alpha = self.values[self.variation_count - 1];
            if alpha < self.params.upper_bound {
                let m = self.params.searchmoves[self.current_move_index];
                assert!(self.params.position.do_move(m));
                self.previously_searched_nodes += 1;
                self.searcher.start_search(SearchParams {
                                               search_id: 0,
                                               depth: self.params.depth - 1,
                                               lower_bound: -self.params.upper_bound,
                                               upper_bound: -max(alpha, self.params.lower_bound),
                                               searchmoves: self.params.position.legal_moves(),
                                               ..self.params.clone()
                                           },
                                           None);
                return true;
            }
        }
        self.write_reslut_to_tt();
        false
    }

    fn write_reslut_to_tt(&self) {
        if self.all_moves_are_considered {
            let value = self.values[0];
            let bound = match value {
                v if v <= self.params.lower_bound => BOUND_UPPER,
                v if v >= self.params.upper_bound => BOUND_LOWER,
                _ => BOUND_EXACT,
            };
            let best_move = self.params.searchmoves[0];
            let p = &self.params.position;
            self.tt.store(p.hash(), <T::HashTable as HashTable>::Entry::with_static_eval(
                value, bound, self.params.depth, best_move.digest(), p.evaluator().evaluate(p.board())));
        }
    }

    fn advance_current_move(&mut self, v: Value) {
        debug_assert!(v >= self.values[self.current_move_index]);
        let mut i = self.current_move_index;
        self.current_move_index += 1;

        // Update `self.values` making sure that it remains sorted.
        self.values[i] = v;
        while i > 0 && v > self.values[i - 1] {
            self.values.swap(i, i - 1);
            self.params.searchmoves.swap(i, i - 1);
            i -= 1;
        }
    }

    #[inline]
    fn runs_genuine_multipv_search(&self) -> bool {
        self.searcher.lmr_mode
    }
}

lazy_static! {
    static ref VARIATION_COUNT: RwLock<usize> = RwLock::new(1);
}
<|endoftext|>


<commit_before>#![cfg_attr(
    not(any(feature = "vulkan", feature = "dx12", feature = "metal", feature = "gl")),
    allow(dead_code)
)]

extern crate gfx_hal as hal;
extern crate gfx_warden as warden;
extern crate ron;
#[macro_use]
extern crate serde;

#[cfg(feature = "env_logger")]
extern crate env_logger;
#[cfg(feature = "vulkan")]
extern crate gfx_backend_vulkan;
#[cfg(feature = "dx12")]
extern crate gfx_backend_dx12;
#[cfg(feature = "metal")]
extern crate gfx_backend_metal;
#[cfg(any(feature = "gl", feature = "gl-headless"))]
extern crate gfx_backend_gl;

use std::collections::HashMap;
use std::fs::File;
use std::path::PathBuf;

use ron::de;

#[derive(Debug, Deserialize)]
enum Expectation {
    Buffer(String, Vec<u8>),
    ImageRow(String, usize, Vec<u8>),
}

#[derive(Debug, Deserialize)]
struct Test {
    features: hal::Features,
    jobs: Vec<String>,
    expect: Expectation,
}

type Suite = HashMap<String, HashMap<String, Test>>;

struct TestGroup {
    name: String,
    scene: warden::raw::Scene,
    tests: HashMap<String, Test>,
}

#[derive(Debug)]
struct TestResults {
    pass: usize,
    skip: usize,
    fail: usize,
}

struct Harness {
    base_path: PathBuf,
    suite: Vec<TestGroup>,
}

impl Harness {
    fn new(suite_name: &str) -> Self {
        let base_path = PathBuf::from(concat!(
            env!("CARGO_MANIFEST_DIR"),
            "/../../reftests",
        ));
        println!("Parsing test suite '{}'...", suite_name);

        let suite_path = base_path
            .join(suite_name)
            .with_extension("ron");
        let suite = File::open(suite_path)
            .map_err(de::Error::from)
            .and_then(de::from_reader::<_, Suite>)
            .expect("failed to open/parse the suite")
            .into_iter()
            .map(|(name, tests)| {
                let path = base_path
                    .join("scenes")
                    .join(&name)
                    .with_extension("ron");
                let scene = File::open(path)
                    .map_err(de::Error::from)
                    .and_then(de::from_reader)
                    .expect("failed to open/parse the scene");
                TestGroup {
                    name,
                    scene,
                    tests,
                }
            })
            .collect();

        Harness {
            base_path,
            suite,
        }
    }

    fn run<I: hal::Instance>(&self, instance: I) -> usize {
        use hal::{PhysicalDevice};

        let mut results = TestResults {
            pass: 0,
            skip: 0,
            fail: 0,
        };
        for tg in &self.suite {
            let mut adapters = instance.enumerate_adapters();
            let adapter = adapters.remove(0);
            let features = adapter.physical_device.get_features();
            let limits = adapter.physical_device.get_limits();
            //println!("\t{:?}", adapter.info);
            println!("\tScene '{}':", tg.name);

            #[cfg(not(feature = "glsl-to-spirv"))]
            {
                let all_spirv = tg.scene.resources
                    .values()
                    .all(|res| match *res {
                        warden::raw::Resource::Shader(ref name) => name.ends_with(".spirv"),
                        _ => true,
                    });
                if !all_spirv {
                    println!("\t\tskipped {} tests (GLSL shaders)", tg.tests.len());
                    results.skip += tg.tests.len();
                    continue
                }
            }

            let mut scene = warden::gpu::Scene::<I::Backend, _>::new(
                adapter,
                &tg.scene,
                self.base_path.join("data"),
            ).unwrap();

            for (test_name, test) in &tg.tests {
                print!("\t\tTest '{}' ...", test_name);
                if !features.contains(test.features) {
                    println!("\tskipped (features missing: {:?})", test.features - features);
                    results.skip += 1;
                }
                let mut max_compute_groups = [0; 3];
                for job_name in &test.jobs {
                    if let warden::raw::Job::Compute { dispatch, .. } = tg.scene.jobs[job_name] {
                         max_compute_groups[0] = max_compute_groups[0].max(dispatch.0);
                         max_compute_groups[1] = max_compute_groups[1].max(dispatch.1);
                         max_compute_groups[2] = max_compute_groups[2].max(dispatch.2);
                    }
                }
                if  max_compute_groups[0] > limits.max_compute_group_size[0] ||
                    max_compute_groups[1] > limits.max_compute_group_size[1] ||
                    max_compute_groups[2] > limits.max_compute_group_size[2]
                {
                    println!("\tskipped (compute {:?})", max_compute_groups);
                    results.skip += 1;
                    continue
                }

                scene.run(test.jobs.iter().map(|x| x.as_str()));

                print!("\tran: ");
                let (guard, row, data) = match test.expect {
                    Expectation::Buffer(ref buffer, ref data) =>
                        (scene.fetch_buffer(buffer), 0, data),
                    Expectation::ImageRow(ref image, row, ref data) =>
                        (scene.fetch_image(image), row, data),
                };

                if data.as_slice() == guard.row(row) {
                    println!("PASS");
                    results.pass += 1;
                } else {
                    println!("FAIL {:?}", guard.row(row));
                    results.fail += 1;
                }

                #[cfg(feature = "metal")]
                {
                    println!("Command buffer re-use is not ready on Metal, exiting");
                    return results.fail + 1;
                }
            }
        }

        println!("\t{:?}", results);
        results.fail
    }
}

fn main() {
    use std::{env, process};

    #[cfg(feature = "env_logger")]
    env_logger::init();
    let mut num_failures = 0;

    let suite_name = match env::args().nth(1) {
        Some(name) => name,
        None => {
            println!("Call with the argument of the reftest suite name");
            return
        }
    };

    let harness = Harness::new(&suite_name);
    #[cfg(feature = "vulkan")]
    {
        println!("Warding Vulkan:");
        let instance = gfx_backend_vulkan::Instance::create("warden", 1);
        num_failures += harness.run(instance);
    }
    #[cfg(feature = "dx12")]
    {
        println!("Warding DX12:");
        let instance = gfx_backend_dx12::Instance::create("warden", 1);
        num_failures += harness.run(instance);
    }
    #[cfg(feature = "metal")]
    {
        println!("Warding Metal:");
        let instance = gfx_backend_metal::Instance::create("warden", 1);
        num_failures += harness.run(instance);
    }
    #[cfg(feature = "gl")]
    {
        use gfx_backend_gl::glutin;
        println!("Warding GL:");
        let events_loop = glutin::EventsLoop::new();
        let window = glutin::GlWindow::new(
            glutin::WindowBuilder::new(),
            glutin::ContextBuilder::new()
                .with_gl_profile(glutin::GlProfile::Core),
            &events_loop,
            ).unwrap();
        let instance = gfx_backend_gl::Surface::from_window(window);
        num_failures += harness.run(instance);
    }
    #[cfg(feature = "gl-headless")]
    {
        println!("Warding GL headless:");
        let context = gfx_backend_gl::glutin::HeadlessRendererBuilder::new(1, 1)
            .build()
            .unwrap();
        let instance = gfx_backend_gl::Headless(context);
        num_failures += harness.run(instance);
    }
    let _ = harness;
    num_failures += 0; // mark as mutated
    process::exit(num_failures as _);
}
<commit_msg>Warden temporary disabilities<commit_after>#![cfg_attr(
    not(any(feature = "vulkan", feature = "dx12", feature = "metal", feature = "gl")),
    allow(dead_code)
)]

extern crate gfx_hal as hal;
extern crate gfx_warden as warden;
extern crate ron;
#[macro_use]
extern crate serde;

#[cfg(feature = "env_logger")]
extern crate env_logger;
#[cfg(feature = "vulkan")]
extern crate gfx_backend_vulkan;
#[cfg(feature = "dx12")]
extern crate gfx_backend_dx12;
#[cfg(feature = "metal")]
extern crate gfx_backend_metal;
#[cfg(any(feature = "gl", feature = "gl-headless"))]
extern crate gfx_backend_gl;

use std::collections::HashMap;
use std::fs::File;
use std::path::PathBuf;

use ron::de;

#[derive(Debug, Deserialize)]
enum Expectation {
    Buffer(String, Vec<u8>),
    ImageRow(String, usize, Vec<u8>),
}

#[derive(Debug, Deserialize)]
struct Test {
    features: hal::Features,
    jobs: Vec<String>,
    expect: Expectation,
}

type Suite = HashMap<String, HashMap<String, Test>>;

struct TestGroup {
    name: String,
    scene: warden::raw::Scene,
    tests: HashMap<String, Test>,
}

#[derive(Debug)]
struct TestResults {
    pass: usize,
    skip: usize,
    fail: usize,
}

#[derive(Default)]
struct Disabilities {
    no_command_buffer_reuse: bool,
}

struct Harness {
    base_path: PathBuf,
    suite: Vec<TestGroup>,
}

impl Harness {
    fn new(suite_name: &str) -> Self {
        let base_path = PathBuf::from(concat!(
            env!("CARGO_MANIFEST_DIR"),
            "/../../reftests",
        ));
        println!("Parsing test suite '{}'...", suite_name);

        let suite_path = base_path
            .join(suite_name)
            .with_extension("ron");
        let suite = File::open(suite_path)
            .map_err(de::Error::from)
            .and_then(de::from_reader::<_, Suite>)
            .expect("failed to open/parse the suite")
            .into_iter()
            .map(|(name, tests)| {
                let path = base_path
                    .join("scenes")
                    .join(&name)
                    .with_extension("ron");
                let scene = File::open(path)
                    .map_err(de::Error::from)
                    .and_then(de::from_reader)
                    .expect("failed to open/parse the scene");
                TestGroup {
                    name,
                    scene,
                    tests,
                }
            })
            .collect();

        Harness {
            base_path,
            suite,
        }
    }

    fn run<I: hal::Instance>(
        &self,
        instance: I,
        disabilities: Disabilities,
    ) -> usize {
        use hal::{PhysicalDevice};

        let mut results = TestResults {
            pass: 0,
            skip: 0,
            fail: 0,
        };
        for tg in &self.suite {
            let mut adapters = instance.enumerate_adapters();
            let adapter = adapters.remove(0);
            let features = adapter.physical_device.get_features();
            let limits = adapter.physical_device.get_limits();
            //println!("\t{:?}", adapter.info);
            println!("\tScene '{}':", tg.name);

            #[cfg(not(feature = "glsl-to-spirv"))]
            {
                let all_spirv = tg.scene.resources
                    .values()
                    .all(|res| match *res {
                        warden::raw::Resource::Shader(ref name) => name.ends_with(".spirv"),
                        _ => true,
                    });
                if !all_spirv {
                    println!("\t\tskipped {} tests (GLSL shaders)", tg.tests.len());
                    results.skip += tg.tests.len();
                    continue
                }
            }

            let mut scene = warden::gpu::Scene::<I::Backend, _>::new(
                adapter,
                &tg.scene,
                self.base_path.join("data"),
            ).unwrap();

            for (test_name, test) in &tg.tests {
                print!("\t\tTest '{}' ...", test_name);
                if !features.contains(test.features) {
                    println!("\tskipped (features missing: {:?})", test.features - features);
                    results.skip += 1;
                }
                let mut max_compute_groups = [0; 3];
                for job_name in &test.jobs {
                    if let warden::raw::Job::Compute { dispatch, .. } = tg.scene.jobs[job_name] {
                         max_compute_groups[0] = max_compute_groups[0].max(dispatch.0);
                         max_compute_groups[1] = max_compute_groups[1].max(dispatch.1);
                         max_compute_groups[2] = max_compute_groups[2].max(dispatch.2);
                    }
                }
                if  max_compute_groups[0] > limits.max_compute_group_size[0] ||
                    max_compute_groups[1] > limits.max_compute_group_size[1] ||
                    max_compute_groups[2] > limits.max_compute_group_size[2]
                {
                    println!("\tskipped (compute {:?})", max_compute_groups);
                    results.skip += 1;
                    continue
                }

                scene.run(test.jobs.iter().map(|x| x.as_str()));

                print!("\tran: ");
                let (guard, row, data) = match test.expect {
                    Expectation::Buffer(ref buffer, ref data) =>
                        (scene.fetch_buffer(buffer), 0, data),
                    Expectation::ImageRow(ref image, row, ref data) =>
                        (scene.fetch_image(image), row, data),
                };

                if data.as_slice() == guard.row(row) {
                    println!("PASS");
                    results.pass += 1;
                } else {
                    println!("FAIL {:?}", guard.row(row));
                    results.fail += 1;
                }

                if disabilities.no_command_buffer_reuse {
                    println!("Command buffer re-use is not ready, exiting");
                    return results.fail;
                }
            }
        }

        println!("\t{:?}", results);
        results.fail
    }
}

fn main() {
    use std::{env, process};

    #[cfg(feature = "env_logger")]
    env_logger::init();
    let mut num_failures = 0;

    let suite_name = match env::args().nth(1) {
        Some(name) => name,
        None => {
            println!("Call with the argument of the reftest suite name");
            return
        }
    };

    let harness = Harness::new(&suite_name);
    #[cfg(feature = "vulkan")]
    {
        println!("Warding Vulkan:");
        let instance = gfx_backend_vulkan::Instance::create("warden", 1);
        num_failures += harness.run(instance, Disabilities::default());
    }
    #[cfg(feature = "dx12")]
    {
        println!("Warding DX12:");
        let instance = gfx_backend_dx12::Instance::create("warden", 1);
        num_failures += harness.run(instance, Disabilities::default());
    }
    #[cfg(feature = "metal")]
    {
        println!("Warding Metal:");
        let instance = gfx_backend_metal::Instance::create("warden", 1);
        num_failures += harness.run(instance, Disabilities {
            no_command_buffer_reuse: true,
            .. Disabilities::default()
        });
    }
    #[cfg(feature = "gl")]
    {
        use gfx_backend_gl::glutin;
        println!("Warding GL:");
        let events_loop = glutin::EventsLoop::new();
        let window = glutin::GlWindow::new(
            glutin::WindowBuilder::new(),
            glutin::ContextBuilder::new()
                .with_gl_profile(glutin::GlProfile::Core),
            &events_loop,
            ).unwrap();
        let instance = gfx_backend_gl::Surface::from_window(window);
        num_failures += harness.run(instance, Disabilities::default());
    }
    #[cfg(feature = "gl-headless")]
    {
        println!("Warding GL headless:");
        let context = gfx_backend_gl::glutin::HeadlessRendererBuilder::new(1, 1)
            .build()
            .unwrap();
        let instance = gfx_backend_gl::Headless(context);
        num_failures += harness.run(instance, Disabilities::default());
    }
    let _ = harness;
    num_failures += 0; // mark as mutated
    process::exit(num_failures as _);
}
<|endoftext|>


<commit_before>
extern crate glob;

use std::fs::canonicalize;
use std::path::PathBuf;
use std::process::Command;
use glob::glob;

fn search_lib(libpath: &PathBuf, regex: &str) -> PathBuf {
    glob(libpath.join(regex).to_str().unwrap()).unwrap().last().unwrap().unwrap()
}

fn create_symlink(libpath: &PathBuf, lib: &PathBuf, name: &str) {
    Command::new("ln")
        .arg("-sf")
        .arg(lib.file_name().unwrap())
        .arg(name)
        .current_dir(&libpath)
        .status()
        .expect("Failed to create symlink");
}

fn main() {
    let source = PathBuf::from("numpy");
    Command::new("python").args(&["setup.py", "build"]).current_dir(&source).status().expect("Failed to build numpy");
    let libpath = canonicalize(PathBuf::from("numpy/build/lib.linux-x86_64-3.6/numpy/core")).unwrap();
    let multiarray = search_lib(&libpath, "multiarray.*.so");
    let umath = search_lib(&libpath, "umath.*.so");
    create_symlink(&libpath, &multiarray, "libmultiarray.so");
    create_symlink(&libpath, &umath, "libumath.so");
    println!("cargo:rustc-link-search={}", libpath.display());
    println!("cargo:rustc-link-lib=dylib=multiarray");
    println!("cargo:rustc-link-lib=dylib=umath");
}
<commit_msg>BUILD: Use python3<commit_after>
extern crate glob;

use std::fs::canonicalize;
use std::path::PathBuf;
use std::process::Command;
use glob::glob;

fn glob1(regex: &str) -> PathBuf {
    glob(regex).unwrap().last().unwrap().unwrap()
}

fn search_lib(libpath: &PathBuf, regex: &str) -> PathBuf {
    glob1(libpath.join(regex).to_str().unwrap())
}

fn create_symlink(libpath: &PathBuf, lib: &PathBuf, name: &str) {
    Command::new("ln")
        .arg("-sf")
        .arg(lib.file_name().unwrap())
        .arg(name)
        .current_dir(&libpath)
        .status()
        .expect("Failed to create symlink");
}

fn main() {
    let source = PathBuf::from("numpy");
    Command::new("python3").args(&["setup.py", "build"]).current_dir(&source).status().expect("Failed to build numpy");
    let libpath = canonicalize(glob1("numpy/build/lib.*/numpy/core")).unwrap();
    let multiarray = search_lib(&libpath, "multiarray.*.so");
    let umath = search_lib(&libpath, "umath.*.so");
    create_symlink(&libpath, &multiarray, "libmultiarray.so");
    create_symlink(&libpath, &umath, "libumath.so");
    println!("cargo:rustc-link-search={}", libpath.display());
    println!("cargo:rustc-link-lib=dylib=multiarray");
    println!("cargo:rustc-link-lib=dylib=umath");
}
<|endoftext|>


<commit_before>extern crate x11;
extern crate libc;

use std::ffi;
use std::process::Command;
use std::boxed::Box;
use std::ptr;

use x11::xlib;
use x11::xlib::{ Display, Window };
use super::WindowManager;
use super::workspace::Workspaces;
use super::layout;

#[derive(Hash, Eq, PartialEq, Debug)]
pub struct KeyBind {
    pub key: u64,
    pub mask: u32,
}

impl KeyBind {
    pub fn build(mod_key: u32, tokens: &[&str]) -> KeyBind {
        let mut mask = 0;
        let mut sym = 0;
        for key in tokens {
            match *key {
                "$mod" => mask = mask | mod_key,
                "Shift" => mask = mask | xlib::ShiftMask,
                "Ctrl" => mask = mask | xlib::ControlMask,
                "Mod1" => mask = mask | xlib::Mod1Mask,
                "Mod2" => mask = mask | xlib::Mod2Mask,
                "Mod3" => mask = mask | xlib::Mod3Mask,
                "Mod4" => mask = mask | xlib::Mod4Mask,
                "Mod5" => mask = mask | xlib::Mod5Mask,
                _ => {
                    let tmp = ffi::CString::new(*key).unwrap();
                    unsafe{
                        sym = xlib::XStringToKeysym(tmp.as_ptr());
                    }
                }
            }
        }

        println!("bind {} {}", mask, sym);
        KeyBind {
            mask: mask,
            key: sym
        }
    }
}

pub trait Handler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int);
}

pub struct ExecHandler {
    pub cmd: Command
}

pub struct LayoutHandler {
    layout_type: layout::Type,
}

/// switch to another workspace
pub struct WorkspaceHandler {
    pub key: char,
}

/// move window to target workspace
pub struct WindowToWorkspaceHandler {
    pub key: char,
}

pub struct WindowFocusHandler {
    pub direction: layout::Direction,
}

impl Handler for WindowFocusHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int) {
        debug!("change focus in current workspace");
        let mut window: Window = 0;
        let mut revert_to: libc::c_int = 0;
        unsafe {
            let s = xlib::XGetInputFocus(display, &mut window, &mut revert_to);
            println!("window {}", window);
            let current = workspaces.current();
            match current.contain(window) {
                Some(i) => {
                    let next = if (i+1) >= current.size() { 0 } else { i+1 };
                    xlib::XSetInputFocus(display, current.get(next), 0, 0);
                }
                None => {}
            }
        }
    }
}
impl Handler for WindowToWorkspaceHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int) {
        debug!("handle window move form {} to {}", workspaces.current_name(), self.key);
        let mut window: Window = 0;
        let mut revert_to: libc::c_int = 0;
        unsafe{
            let s = xlib::XGetInputFocus(display, &mut window, &mut revert_to);
            println!("window {}", window);
        }

        let mut root: Window = 0;
        let mut parent: Window = window;
        let mut children: *mut Window = ptr::null_mut();
        let mut nchildren: libc::c_uint = 0;

        // while parent != root {
            window = parent;
            unsafe{
                let s = xlib::XQueryTree(display, window, &mut root, &mut parent, &mut children, &mut nchildren);
                if s > 0 {
                    println!("parent {} root {}", parent, root);
                    xlib::XFree(children as *mut libc::c_void);
                }
                else{
                    println!("error");
                }
            }
        // }

        println!("focused window {}", window);
        workspaces.current().p();
        let from = workspaces.current_name();
        workspaces.move_window(window, from, self.key);
        workspaces.current().config(display, screen_num);

        match workspaces.get(self.key) {
            Some(w) => {
                w.config(display, screen_num);
            }
            None => {}
        }

    }
}

impl Handler for WorkspaceHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int) {
        debug!("handle workspace");
        workspaces.switch_current(self.key, display);
    }
}

impl Handler for ExecHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int) {
        debug!("handle exec");
        self.cmd.spawn();
    }
}

impl Handler for LayoutHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut xlib::Display, screen_num: libc::c_int) {
        debug!("handle layout");
        let current = workspaces.current();
        let t = self.layout_type.clone();
        current.change_layout(t);
        current.config(display, screen_num);
    }
}

impl LayoutHandler {
    pub fn new(layout: layout::Type) -> LayoutHandler{
        LayoutHandler {
            layout_type: layout
        }
    }
}

impl ExecHandler {
    pub fn new(tokens: &[&str]) -> ExecHandler {
        let (name, args) = tokens.split_at(1);
        let mut cmd = Command::new(name[0]);

        for arg in args {
            println!("{}", arg);
            cmd.arg(arg);
        }

        let handler = ExecHandler {
            cmd: cmd,
        };
        handler
    }
}
<commit_msg>close window handler<commit_after>extern crate x11;
extern crate libc;

use std::ffi;
use std::mem;
use std::ptr;
use std::process::Command;
use std::boxed::Box;

use x11::xlib;
use x11::xlib::{ Display, Window };
use super::WindowManager;
use super::workspace::Workspaces;
use super::layout;
use super::super::libx;

#[derive(Hash, Eq, PartialEq, Debug)]
pub struct KeyBind {
    pub key: u64,
    pub mask: u32,
}

impl KeyBind {
    pub fn build(mod_key: u32, tokens: &[&str]) -> KeyBind {
        let mut mask = 0;
        let mut sym = 0;
        for key in tokens {
            match *key {
                "$mod" => mask = mask | mod_key,
                "Shift" => mask = mask | xlib::ShiftMask,
                "Ctrl" => mask = mask | xlib::ControlMask,
                "Mod1" => mask = mask | xlib::Mod1Mask,
                "Mod2" => mask = mask | xlib::Mod2Mask,
                "Mod3" => mask = mask | xlib::Mod3Mask,
                "Mod4" => mask = mask | xlib::Mod4Mask,
                "Mod5" => mask = mask | xlib::Mod5Mask,
                _ => {
                    let tmp = ffi::CString::new(*key).unwrap();
                    unsafe{
                        sym = xlib::XStringToKeysym(tmp.as_ptr());
                    }
                }
            }
        }

        println!("bind {} {}", mask, sym);
        KeyBind {
            mask: mask,
            key: sym
        }
    }
}

pub trait Handler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int);
}

pub struct ExecHandler {
    pub cmd: Command
}

pub struct LayoutHandler {
    layout_type: layout::Type,
}

/// switch to another workspace
pub struct WorkspaceHandler {
    pub key: char,
}

/// move window to target workspace
pub struct WindowToWorkspaceHandler {
    pub key: char,
}

pub struct WindowFocusHandler {
    pub direction: layout::Direction,
}

pub struct WindowCloseHandler;

impl Handler for WindowCloseHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int) {
        debug!("handle window close");
        let mut window: Window = 0;
        let mut revert_to: libc::c_int = 0;
        unsafe{
            let s = xlib::XGetInputFocus(display, &mut window, &mut revert_to);

            let mut event: xlib::XClientMessageEvent = mem::zeroed();

            let wm_delete_window = libx::get_atom(display, "WM_DELETE_WINDOW");
            let wm_protocols = libx::get_atom(display, "WM_PROTOCOLS");

            println!("wm delete window {}", wm_delete_window);
            println!("protocols {}", wm_protocols);

            event.type_ = xlib::ClientMessage;
            event.message_type = wm_protocols;
            event.format = 32;
            event.window = window;
            event.send_event = xlib::True;
            event.display = display;
            event.data.set_long(0, wm_delete_window as libc::c_long);

            let mut e: xlib::XEvent = From::from(event);
            xlib::XSendEvent(display, window, xlib::True, xlib::NoEventMask, &mut e);

            // xlib::XWithdrawWindow(display, window, screen_num);
            // xlib::XDestroyWindow(display, window);
            println!("destroy {}", window);
        }

    }
}
impl Handler for WindowFocusHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int) {
        debug!("change focus in current workspace");
        let mut window: Window = 0;
        let mut revert_to: libc::c_int = 0;
        unsafe {
            let s = xlib::XGetInputFocus(display, &mut window, &mut revert_to);
            println!("window {}", window);
            let current = workspaces.current();
            match current.contain(window) {
                Some(i) => {
                    let next = if (i+1) >= current.size() { 0 } else { i+1 };
                    xlib::XSetInputFocus(display, current.get(next), 0, 0);
                }
                None => {}
            }
        }
    }
}

impl Handler for WindowToWorkspaceHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int) {
        debug!("handle window move form {} to {}", workspaces.current_name(), self.key);
        let mut window: Window = 0;
        let mut revert_to: libc::c_int = 0;
        unsafe{
            let s = xlib::XGetInputFocus(display, &mut window, &mut revert_to);
            println!("window {}", window);
        }

        let mut root: Window = 0;
        let mut parent: Window = window;
        let mut children: *mut Window = ptr::null_mut();
        let mut nchildren: libc::c_uint = 0;

        while parent != root {
            window = parent;
            unsafe{
                let s = xlib::XQueryTree(display, window, &mut root, &mut parent, &mut children, &mut nchildren);
                if s > 0 {
                    println!("parent {} root {}", parent, root);
                    xlib::XFree(children as *mut libc::c_void);
                }
                else{
                    println!("error");
                }
            }
        }

        println!("focused window {}", window);
        workspaces.current().p();
        let from = workspaces.current_name();
        workspaces.move_window(window, from, self.key);
        workspaces.current().config(display, screen_num);

        match workspaces.get(self.key) {
            Some(w) => {
                w.config(display, screen_num);
            }
            None => {}
        }

    }
}

impl Handler for WorkspaceHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int) {
        debug!("handle workspace");
        workspaces.switch_current(self.key, display);

    }
}

impl Handler for ExecHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int) {
        debug!("handle exec");
        self.cmd.spawn();
    }
}

impl Handler for LayoutHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut xlib::Display, screen_num: libc::c_int) {
        debug!("handle layout");
        let current = workspaces.current();
        let t = self.layout_type.clone();
        current.change_layout(t);
        current.config(display, screen_num);
    }
}

impl LayoutHandler {
    pub fn new(layout: layout::Type) -> LayoutHandler{
        LayoutHandler {
            layout_type: layout
        }
    }
}

impl ExecHandler {
    pub fn new(tokens: &[&str]) -> ExecHandler {
        let (name, args) = tokens.split_at(1);
        let mut cmd = Command::new(name[0]);

        for arg in args {
            println!("{}", arg);
            cmd.arg(arg);
        }

        let handler = ExecHandler {
            cmd: cmd,
        };
        handler
    }
}
<|endoftext|>