<commit_before>extern crate rustc_version;

use std::env;
use std::path::{Path};
use std::process::{Command};

const SEARCH_LINUX: &'static [&'static str] = &[
    "/usr/lib",
    "/usr/lib/llvm",
    "/usr/lib/llvm-3.8/lib",
    "/usr/lib/llvm-3.7/lib",
    "/usr/lib/llvm-3.6/lib",
    "/usr/lib/llvm-3.5/lib",
    "/usr/lib/llvm-3.4/lib",
    "/usr/lib64/llvm",
    "/usr/lib/x86_64-linux-gnu",
    "/usr/local/lib",
];

const SEARCH_OSX: &'static [&'static str] = &[
    "/usr/local/opt/llvm/lib",
    "/Library/Developer/CommandLineTools/usr/lib",
    "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib",
];

const SEARCH_WINDOWS: &'static [&'static str] = &[
    "C:\\Program Files\\LLVM\\bin",
    "C:\\Program Files\\LLVM\\lib",
];

fn run(command: &str, arguments: &[&str]) -> Option<String> {
    Command::new(command).args(arguments).output().map(|o| {
        String::from_utf8_lossy(&o.stdout).into_owned()
    }).ok()
}

fn find_libclang() -> Option<(String, Option<String>)> {
    let search = if let Ok(directory) = env::var("LIBCLANG_PATH") {
        vec![directory]
    } else {
        run("llvm-config", &["--libdir"]).map(|d| vec![d]).unwrap_or_else(|| {
            if cfg!(any(target_os="freebsd", target_os="linux")) {
                SEARCH_LINUX
            } else if cfg!(target_os="osx") {
                SEARCH_OSX
            } else if cfg!(target_os="windows") {
                SEARCH_WINDOWS
            } else {
                panic!("unsupported operating system!");
            }.into_iter().map(|s| s.to_string()).collect()
        })
    };

    let library = if cfg!(target_os="windows") {
        format!("libclang{}", env::consts::DLL_SUFFIX)
    } else {
        format!("{}clang{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX)
    };

    let directory = search.into_iter().find(|d| Path::new(&d).join(&library).exists());

    if directory.is_none() && cfg!(target_os="linux") {
        run("/sbin/ldconfig", &["-p"]).unwrap().lines().map(|l| l.trim()).find(|l| {
            l.starts_with(&library)
        }).and_then(|l| {
            let path = l.rsplit(" ").next().map(|p| Path::new(p));
            if path.map_or(false, |p| p.exists()) {
                let path = path.unwrap();
                let directory = path.parent().unwrap().to_str().unwrap().into();
                let file = path.file_name().unwrap().to_str().unwrap().into();
                Some((directory, Some(file)))
            } else {
                None
            }
        })
    } else {
        directory.map(|d| (d, None))
    }
}

const LIBRARIES: &'static [&'static str] = &[
    "LLVMAnalysis",
    "LLVMBitReader",
    "LLVMCore",
    "LLVMLTO",
    "LLVMLinker",
    "LLVMMC",
    "LLVMMCParser",
    "LLVMObjCARCOpts",
    "LLVMObject",
    "LLVMOption",
    "LLVMScalarOpts",
    "LLVMSupport",
    "LLVMTarget",
    "LLVMTransformUtils",
    "LLVMVectorize",
    "LLVMipa",
    "LLVMipo",
    "clang",
    "clangARCMigrate",
    "clangAST",
    "clangASTMatchers",
    "clangAnalysis",
    "clangBasic",
    "clangDriver",
    "clangEdit",
    "clangFormat",
    "clangFrontend",
    "clangIndex",
    "clangLex",
    "clangParse",
    "clangRewrite",
    "clangRewriteFrontend",
    "clangSema",
    "clangSerialization",
    "clangStaticAnalyzerCheckers",
    "clangStaticAnalyzerCore",
    "clangStaticAnalyzerFrontend",
    "clangTooling",
];

fn get_libraries() -> Vec<String> {
    run("llvm-config", &["--libs"]).map(|o| {
        o.split_whitespace().filter_map(|p| {
            Path::new(p).file_stem().map(|l| l.to_string_lossy()[3..].into())
        }).collect()
    }).unwrap_or_else(|| LIBRARIES.iter().map(|l| (*l).into()).collect())
}

fn main() {
    if let Some((directory, file)) = find_libclang() {
        if cfg!(feature="static") || env::var("LIBCLANG_STATIC").is_ok() {
            print!("cargo:rustc-flags=");
            if let Ok(directory) = env::var("LIBCLANG_STATIC_PATH") {
                print!("-L {} ", directory);
            }
            for library in get_libraries() {
                print!("-l static={} ", library)
            }
            println!("-L {} -l ncursesw -l z -l stdc++", directory);
        } else {
            println!("cargo:rustc-link-search={}", directory);
            if let Some(file) = file {
                println!("cargo:rustc-link-lib=dylib=:{}", file);
            } else {
                println!("cargo:rustc-link-lib=dylib=clang");
            }
        }
    } else {
        panic!("unable to find libclang!");
    }

    if rustc_version::version_matches("<=1.5.*") {
        println!("cargo:rustc-cfg={}", "lte_rustc_1_5");
    }
}
<commit_msg>Improve build (#7)<commit_after>extern crate rustc_version;

use std::env;
use std::path::{Path};
use std::process::{Command};

const SEARCH_OSX: &'static [&'static str] = &[
    "/usr/local/opt/llvm/lib",
    "/Library/Developer/CommandLineTools/usr/lib",
    "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib",
];

const SEARCH_WINDOWS: &'static [&'static str] = &[
    "C:\\Program Files\\LLVM\\bin",
    "C:\\Program Files\\LLVM\\lib",
];

fn run(command: &str, arguments: &[&str]) -> Option<String> {
    Command::new(command).args(arguments).output().map(|o| {
        String::from_utf8_lossy(&o.stdout).into_owned()
    }).ok()
}

fn find_libclang() -> Option<(String, String)> {
    let search = if let Ok(directory) = env::var("LIBCLANG_PATH") {
        vec![directory]
    } else {
        run("llvm-config", &["--libdir"]).map(|d| vec![d]).unwrap_or_else(|| {
            if cfg!(target_os="osx") {
                SEARCH_OSX
            } else if cfg!(target_os="windows") {
                SEARCH_WINDOWS
            } else {
                panic!("unsupported operating system!");
            }.into_iter().map(|s| s.to_string()).collect()
        })
    };

    let library = format!("{}clang{}",
                          env::consts::DLL_PREFIX,
                          env::consts::DLL_SUFFIX);

    let directory = search.into_iter().find(|d| Path::new(&d).join(&library).exists());

    if directory.is_none() && cfg!(target_os="linux") {
        if let Some(output) = run("llvm-config", &["--libdir"]) {
            output.lines()
                .next()
                .map(|l| (l.into(), library))
        } else {
            None
        }
    } else {
        directory.map(|d| (d, library))
    }
}

const LIBRARIES: &'static [&'static str] = &[
    "LLVMAnalysis",
    "LLVMBitReader",
    "LLVMCore",
    "LLVMLTO",
    "LLVMLinker",
    "LLVMMC",
    "LLVMMCParser",
    "LLVMObjCARCOpts",
    "LLVMObject",
    "LLVMOption",
    "LLVMScalarOpts",
    "LLVMSupport",
    "LLVMTarget",
    "LLVMTransformUtils",
    "LLVMVectorize",
    "LLVMipa",
    "LLVMipo",
    "clang",
    "clangARCMigrate",
    "clangAST",
    "clangASTMatchers",
    "clangAnalysis",
    "clangBasic",
    "clangDriver",
    "clangEdit",
    "clangFormat",
    "clangFrontend",
    "clangIndex",
    "clangLex",
    "clangParse",
    "clangRewrite",
    "clangRewriteFrontend",
    "clangSema",
    "clangSerialization",
    "clangStaticAnalyzerCheckers",
    "clangStaticAnalyzerCore",
    "clangStaticAnalyzerFrontend",
    "clangTooling",
];

fn get_libraries() -> Vec<String> {
    run("llvm-config", &["--libs"]).map(|o| {
        o.split_whitespace().filter_map(|p| {
            Path::new(p).file_stem().map(|l| l.to_string_lossy()[2..].into())
        }).collect()
    }).unwrap_or_else(|| LIBRARIES.iter().map(|l| (*l).into()).collect())
}

fn main() {
    let (directory, file) = find_libclang().expect("unable to find libclang!");

    if cfg!(feature="static") || env::var("LIBCLANG_STATIC").is_ok() {
        print!("cargo:rustc-flags=");
        if let Ok(directory) = env::var("LIBCLANG_STATIC_PATH") {
            print!("-L {} ", directory);
        }
        for library in get_libraries() {
            print!("-l static={} ", library)
        }
        println!("-L {} -l ncursesw -l z -l stdc++", directory);
    } else {
        println!("cargo:rustc-link-search={}", directory);
        println!("cargo:rustc-link-lib=dylib=:{}", file);
    }
}
<|endoftext|>


<commit_before>extern crate gcc;
extern crate semver;

use semver::{Version, VersionReq};
use semver::ParseError::IncorrectParse;
use std::process::Command;

/// Get the output from running `llvm-config` with the given argument.
fn llvm_config(arg: &str) -> String {
    let stdout = Command::new("llvm-config")
        .arg(arg)
        .output()
        .ok().expect("llvm-config not found. Install LLVM before attempting to build.")
        .stdout;

    String::from_utf8(stdout).ok().expect("llvm-config output was not UTF-8.")
}

/// Get the LLVM version using llvm-config.
fn llvm_version() -> Version {
    match Version::parse(&llvm_config("--version")) {
        // Ignore partial error; particularly constructs like '3.8.0svn' should be accepted,
        // despite being invalid semver.
        Err(IncorrectParse(v, _)) | Ok(v) => v,
        _ => panic!("Could not determine LLVM version from llvm-config."),
    }
}

fn main() {
    // Check for LLVM 3.6 or greater.
    let minimum_llvm_version = VersionReq::parse(">=3.6").unwrap();
    let version = llvm_version();
    if minimum_llvm_version.matches(&version) {
        println!("Found LLVM version {}", version);
    } else {
        panic!("LLVM version 3.6 or higher is required. (Found {})", version);
    };

    // Parse library linking flags from llvm-config.
    for arg in llvm_config("--ldflags").split_whitespace() {
        if arg.starts_with("-L") {
            println!("cargo:rustc-link-search=native={}", &arg[2..]);
        }
    }

    for arg in llvm_config("--libs").split_whitespace() {
        if arg.starts_with("-l") {
            println!("cargo:rustc-link-lib=static={}", &arg[2..]);
        }
    }

    for arg in llvm_config("--system-libs").split_whitespace() {
        if arg.starts_with("-l") {
            println!("cargo:rustc-link-lib=dylib={}", &arg[2..]);
        }
    }

    // This breaks the link step on Windows with MSVC.
    if !cfg!(windows) {
        // Determine which C++ standard library to use: LLVM's or GCC's.
        let cxxflags = llvm_config("--cxxflags");
        let libcpp = if cxxflags.contains("stdlib=libc++") { "c++" } else { "stdc++" };
        println!("cargo:rustc-link-lib={}", libcpp);
    }

    // Build the extra wrapper functions.
    std::env::set_var("CFLAGS", llvm_config("--cflags").trim());
    gcc::compile_library("libtargetwrappers.a", &["wrappers/target.c"]);
}
<commit_msg>Use a more accurate message for llvm-config errors.<commit_after>extern crate gcc;
extern crate semver;

use semver::{Version, VersionReq};
use semver::ParseError::IncorrectParse;
use std::process::Command;

/// Get the output from running `llvm-config` with the given argument.
fn llvm_config(arg: &str) -> String {
    let stdout = Command::new("llvm-config")
        .arg(arg)
        .output()
        .unwrap_or_else(|e| panic!("Couldn't execute llvm-config. Error: {}", e))
        .stdout;

    String::from_utf8(stdout).ok().expect("llvm-config output was not UTF-8.")
}

/// Get the LLVM version using llvm-config.
fn llvm_version() -> Version {
    match Version::parse(&llvm_config("--version")) {
        // Ignore partial error; particularly constructs like '3.8.0svn' should be accepted,
        // despite being invalid semver.
        Err(IncorrectParse(v, _)) | Ok(v) => v,
        _ => panic!("Could not determine LLVM version from llvm-config."),
    }
}

fn main() {
    // Check for LLVM 3.6 or greater.
    let minimum_llvm_version = VersionReq::parse(">=3.6").unwrap();
    let version = llvm_version();
    if minimum_llvm_version.matches(&version) {
        println!("Found LLVM version {}", version);
    } else {
        panic!("LLVM version 3.6 or higher is required. (Found {})", version);
    };

    // Parse library linking flags from llvm-config.
    for arg in llvm_config("--ldflags").split_whitespace() {
        if arg.starts_with("-L") {
            println!("cargo:rustc-link-search=native={}", &arg[2..]);
        }
    }

    for arg in llvm_config("--libs").split_whitespace() {
        if arg.starts_with("-l") {
            println!("cargo:rustc-link-lib=static={}", &arg[2..]);
        }
    }

    for arg in llvm_config("--system-libs").split_whitespace() {
        if arg.starts_with("-l") {
            println!("cargo:rustc-link-lib=dylib={}", &arg[2..]);
        }
    }

    // This breaks the link step on Windows with MSVC.
    if !cfg!(windows) {
        // Determine which C++ standard library to use: LLVM's or GCC's.
        let cxxflags = llvm_config("--cxxflags");
        let libcpp = if cxxflags.contains("stdlib=libc++") { "c++" } else { "stdc++" };
        println!("cargo:rustc-link-lib={}", libcpp);
    }

    // Build the extra wrapper functions.
    std::env::set_var("CFLAGS", llvm_config("--cflags").trim());
    gcc::compile_library("libtargetwrappers.a", &["wrappers/target.c"]);
}
<|endoftext|>


<commit_before>extern crate gcc;

fn main() {
    println!("cargo:rustc-link-lib=static=gdi32");
    println!("cargo:rustc-link-lib=static=comdlg32");

    gcc::Config::new()
        .file("src/PDCurses/pdcurses/addch.c") //Common PDCurses files
        .file("src/PDCurses/pdcurses/addchstr.c")
        .file("src/PDCurses/pdcurses/addstr.c")
        .file("src/PDCurses/pdcurses/attr.c")
        .file("src/PDCurses/pdcurses/beep.c")
        .file("src/PDCurses/pdcurses/bkgd.c")
        .file("src/PDCurses/pdcurses/border.c")
        .file("src/PDCurses/pdcurses/clear.c")
        .file("src/PDCurses/pdcurses/color.c")
        .file("src/PDCurses/pdcurses/debug.c")
        .file("src/PDCurses/pdcurses/delch.c")
        .file("src/PDCurses/pdcurses/deleteln.c")
        .file("src/PDCurses/pdcurses/deprec.c")
        .file("src/PDCurses/pdcurses/getch.c")
        .file("src/PDCurses/pdcurses/getstr.c")
        .file("src/PDCurses/pdcurses/getyx.c")
        .file("src/PDCurses/pdcurses/inch.c")
        .file("src/PDCurses/pdcurses/inchstr.c")
        .file("src/PDCurses/pdcurses/initscr.c")
        .file("src/PDCurses/pdcurses/inopts.c")
        .file("src/PDCurses/pdcurses/insch.c")
        .file("src/PDCurses/pdcurses/insstr.c")
        .file("src/PDCurses/pdcurses/instr.c")
        .file("src/PDCurses/pdcurses/kernel.c")
        .file("src/PDCurses/pdcurses/keyname.c")
        .file("src/PDCurses/pdcurses/mouse.c")
        .file("src/PDCurses/pdcurses/move.c")
        .file("src/PDCurses/pdcurses/outopts.c")
        .file("src/PDCurses/pdcurses/overlay.c")
        .file("src/PDCurses/pdcurses/pad.c")
        .file("src/PDCurses/pdcurses/panel.c")
        .file("src/PDCurses/pdcurses/printw.c")
        .file("src/PDCurses/pdcurses/refresh.c")
        .file("src/PDCurses/pdcurses/scanw.c")
        .file("src/PDCurses/pdcurses/scr_dump.c")
        .file("src/PDCurses/pdcurses/scroll.c")
        .file("src/PDCurses/pdcurses/slk.c")
        .file("src/PDCurses/pdcurses/termattr.c")
        .file("src/PDCurses/pdcurses/terminfo.c")
        .file("src/PDCurses/pdcurses/touch.c")
        .file("src/PDCurses/pdcurses/util.c")
        .file("src/PDCurses/pdcurses/window.c")
        .file("src/PDCurses/win32a/pdcclip.c") //win32a implementation files
        .file("src/PDCurses/win32a/pdcdisp.c")
        .file("src/PDCurses/win32a/pdcgetsc.c")
        .file("src/PDCurses/win32a/pdckbd.c")
        .file("src/PDCurses/win32a/pdcscrn.c")
        .file("src/PDCurses/win32a/pdcsetsc.c")
        .file("src/PDCurses/win32a/pdcutil.c")
        .include("src/PDCurses")
        .define("WIDE", Some("Y")) //Build with wide-character (Unicode) support
        .define("UTF8", Some("Y")) //Makes PDCurses ignore the system locale, and treat all narrow-character strings as UTF-8
        .compile("libpdcurses.a");
}

<commit_msg>Link gdi32 and comdlg32 dynamically, makes sense because they're dlls to begin with<commit_after>extern crate gcc;

fn main() {
    println!("cargo:rustc-link-lib=dylib=gdi32");
    println!("cargo:rustc-link-lib=dylib=comdlg32");

    gcc::Config::new()
        .file("src/PDCurses/pdcurses/addch.c") //Common PDCurses files
        .file("src/PDCurses/pdcurses/addchstr.c")
        .file("src/PDCurses/pdcurses/addstr.c")
        .file("src/PDCurses/pdcurses/attr.c")
        .file("src/PDCurses/pdcurses/beep.c")
        .file("src/PDCurses/pdcurses/bkgd.c")
        .file("src/PDCurses/pdcurses/border.c")
        .file("src/PDCurses/pdcurses/clear.c")
        .file("src/PDCurses/pdcurses/color.c")
        .file("src/PDCurses/pdcurses/debug.c")
        .file("src/PDCurses/pdcurses/delch.c")
        .file("src/PDCurses/pdcurses/deleteln.c")
        .file("src/PDCurses/pdcurses/deprec.c")
        .file("src/PDCurses/pdcurses/getch.c")
        .file("src/PDCurses/pdcurses/getstr.c")
        .file("src/PDCurses/pdcurses/getyx.c")
        .file("src/PDCurses/pdcurses/inch.c")
        .file("src/PDCurses/pdcurses/inchstr.c")
        .file("src/PDCurses/pdcurses/initscr.c")
        .file("src/PDCurses/pdcurses/inopts.c")
        .file("src/PDCurses/pdcurses/insch.c")
        .file("src/PDCurses/pdcurses/insstr.c")
        .file("src/PDCurses/pdcurses/instr.c")
        .file("src/PDCurses/pdcurses/kernel.c")
        .file("src/PDCurses/pdcurses/keyname.c")
        .file("src/PDCurses/pdcurses/mouse.c")
        .file("src/PDCurses/pdcurses/move.c")
        .file("src/PDCurses/pdcurses/outopts.c")
        .file("src/PDCurses/pdcurses/overlay.c")
        .file("src/PDCurses/pdcurses/pad.c")
        .file("src/PDCurses/pdcurses/panel.c")
        .file("src/PDCurses/pdcurses/printw.c")
        .file("src/PDCurses/pdcurses/refresh.c")
        .file("src/PDCurses/pdcurses/scanw.c")
        .file("src/PDCurses/pdcurses/scr_dump.c")
        .file("src/PDCurses/pdcurses/scroll.c")
        .file("src/PDCurses/pdcurses/slk.c")
        .file("src/PDCurses/pdcurses/termattr.c")
        .file("src/PDCurses/pdcurses/terminfo.c")
        .file("src/PDCurses/pdcurses/touch.c")
        .file("src/PDCurses/pdcurses/util.c")
        .file("src/PDCurses/pdcurses/window.c")
        .file("src/PDCurses/win32a/pdcclip.c") //win32a implementation files
        .file("src/PDCurses/win32a/pdcdisp.c")
        .file("src/PDCurses/win32a/pdcgetsc.c")
        .file("src/PDCurses/win32a/pdckbd.c")
        .file("src/PDCurses/win32a/pdcscrn.c")
        .file("src/PDCurses/win32a/pdcsetsc.c")
        .file("src/PDCurses/win32a/pdcutil.c")
        .include("src/PDCurses")
        .define("WIDE", Some("Y")) //Build with wide-character (Unicode) support
        .define("UTF8", Some("Y")) //Makes PDCurses ignore the system locale, and treat all narrow-character strings as UTF-8
        .compile("libpdcurses.a");
}
<|endoftext|>


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

use std::process::Command;
use std::env;

fn main() {
    let root = env::var("CARGO_MANIFEST_DIR").unwrap();
    if Command::new("make").current_dir("htslib")
                           .arg("CFLAGS=-g -Wall -O2 -fPIC")
                           .arg("lib-static")
                           .status().unwrap()
                           .success() != true {
        panic!("failed to build htslib");
    }
    if Command::new("gcc").arg("-Ihtslib")
                          .arg("-c")
                          .arg("src/htslib/macros.c")
                          .status().unwrap().success() != true {
        panic!("error building macro wrapper");
    }
    if Command::new("ar").arg("r").arg("libmacros.a").arg("macros.o").status().unwrap().success() != true {
        panic!("error buiding macro wrapper");
    }

    println!("cargo:rustc-flags=-L {}/htslib -L . -l static=hts -l static=macros -l z", root);
}
<commit_msg>Fix path.<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::process::Command;
use std::env;

fn main() {
    let root = env::var("CARGO_MANIFEST_DIR").unwrap();
    if Command::new("make").current_dir("htslib")
                           .arg("CFLAGS=-g -Wall -O2 -fPIC")
                           .arg("lib-static")
                           .status().unwrap()
                           .success() != true {
        panic!("failed to build htslib");
    }
    if Command::new("gcc").arg("-Ihtslib")
                          .arg("-c")
                          .arg("src/htslib/macros.c")
                          .status().unwrap().success() != true {
        panic!("error building macro wrapper");
    }
    if Command::new("ar").arg("r").arg("libmacros.a").arg("macros.o").status().unwrap().success() != true {
        panic!("error buiding macro wrapper");
    }

    println!("cargo:rustc-flags=-L {root}/htslib -L {root} -l static=hts -l static=macros -l z",
             root=root);
}
<|endoftext|>


<commit_before>extern crate curl;
extern crate flate2;
extern crate pkg_config;
extern crate semver;
extern crate tar;

use std::error::Error;
use std::fs::File;
use std::io::BufWriter;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use std::process::Command;
use std::{env, fs};

use curl::easy::Easy;
use flate2::read::GzDecoder;
use semver::Version;
use tar::Archive;

const LIBRARY: &'static str = "tensorflow";
const REPOSITORY: &'static str = "https://github.com/tensorflow/tensorflow.git";
const TARGET: &'static str = "tensorflow:libtensorflow.so";
// `VERSION` and `TAG` are separate because the tag is not always `'v' + VERSION`.
const VERSION: &'static str = "1.0.0";
const TAG: &'static str = "v1.0.0";
const MIN_BAZEL: &'static str = "0.3.2";

macro_rules! get(($name:expr) => (ok!(env::var($name))));
macro_rules! ok(($expression:expr) => ($expression.unwrap()));
macro_rules! log {
    ($fmt:expr) => (println!(concat!("libtensorflow-sys/build.rs:{}: ", $fmt), line!()));
    ($fmt:expr, $($arg:tt)*) => (println!(concat!("libtensorflow-sys/build.rs:{}: ", $fmt),
    line!(), $($arg)*));
}
macro_rules! log_var(($var:ident) => (log!(concat!(stringify!($var), " = {:?}"), $var)));

fn main() {
    if pkg_config::find_library(LIBRARY).is_ok() {
        log!("Returning early because {} was already found", LIBRARY);
        return;
    }

    let force_src = match env::var("TF_RUST_BUILD_FROM_SRC") {
        Ok(s) => s == "true",
        Err(_) => false,
    };
    if !force_src && env::consts::ARCH == "x86_64" && (env::consts::OS == "linux" || env::consts::OS == "macos") {
        install_prebuilt();
    } else {
        build_from_src();
    }
}

fn remove_suffix(value: &mut String, suffix: &str) {
    if value.ends_with(suffix) {
        let n = value.len();
        value.truncate(n - suffix.len());
    }
}

fn extract<P: AsRef<Path>, P2: AsRef<Path>>(archive_path: P, extract_to: P2) {
    let file = File::open(archive_path).unwrap();
    let unzipped = GzDecoder::new(file).unwrap();
    let mut a = Archive::new(unzipped);
    a.unpack(extract_to).unwrap();
}

// Downloads and unpacks a prebuilt binary. Only works for certain platforms.
fn install_prebuilt() {
    // Figure out the file names.
    let os = match env::consts::OS {
        "macos" => "darwin",
        x => x,
    };
    let proc_type = if cfg!(feature = "tensorflow_gpu") {"gpu"} else {"cpu"};
    let binary_url = format!(
        "https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-{}-{}-{}-{}.tar.gz",
        proc_type, os, env::consts::ARCH, VERSION);
    log_var!(binary_url);
    let short_file_name = binary_url.split("/").last().unwrap();
    let mut base_name = short_file_name.to_string();
    remove_suffix(&mut base_name, ".tar.gz");
    log_var!(base_name);
    let download_dir = match env::var("TF_RUST_DOWNLOAD_DIR") {
        Ok(s) => PathBuf::from(s),
        Err(_) => PathBuf::from(&get!("CARGO_MANIFEST_DIR")).join("target"),
    };
    if !download_dir.exists() {
        fs::create_dir(&download_dir).unwrap();
    }
    let file_name = download_dir.join(short_file_name);
    log_var!(file_name);

    // Download the tarball.
    if !file_name.exists() {
        let f = File::create(&file_name).unwrap();
        let mut writer = BufWriter::new(f);
        let mut easy = Easy::new();
        easy.url(&binary_url).unwrap();
        easy.write_function(move |data| {
            Ok(writer.write(data).unwrap())
        }).unwrap();
        easy.perform().unwrap();

        let response_code = easy.response_code().unwrap();
        if response_code != 200 {
            panic!("Unexpected response code {} for {}", response_code, binary_url);
        }
    }

    // Extract the tarball.
    let unpacked_dir = download_dir.join(base_name);
    let lib_dir = unpacked_dir.join("lib");
    let library_file = format!("lib{}.so", LIBRARY);
    let library_full_path = lib_dir.join(&library_file);
    if !library_full_path.exists() {
        extract(file_name, &unpacked_dir);
    }

    //run("find", |command| command); // TODO: remove
    run("ls", |command| {
        command.arg("-l").arg(lib_dir.to_str().unwrap())
        }); // TODO: remove

    println!("cargo:rustc-link-lib=dylib={}", LIBRARY);
    let output = PathBuf::from(&get!("OUT_DIR"));
    let new_library_full_path = output.join(&library_file);
    if new_library_full_path.exists() {
        println!("File {} already exists, deleting.", new_library_full_path.display());
        std::fs::remove_file(&new_library_full_path).unwrap();
    }

    println!("Copying {} to {}...", library_full_path.display(), new_library_full_path.display());
    std::fs::copy(&library_full_path, &new_library_full_path).unwrap();
    println!("cargo:rustc-link-search={}", output.display());
}

fn build_from_src() {
    let output = PathBuf::from(&get!("OUT_DIR"));
    log_var!(output);
    let source = PathBuf::from(&get!("CARGO_MANIFEST_DIR")).join(format!("target/source-{}", TAG));
    log_var!(source);
    let lib_dir = output.join(format!("lib-{}", TAG));
    log_var!(lib_dir);
    if lib_dir.exists() {
        log!("Directory {:?} already exists", lib_dir);
    } else {
        log!("Creating directory {:?}", lib_dir);
        fs::create_dir(lib_dir.clone()).unwrap();
    }
    let library_path = lib_dir.join(format!("lib{}.so", LIBRARY));
    log_var!(library_path);
    if library_path.exists() {
        log!("{:?} already exists, not building", library_path);
    } else {
        if let Err(e) = check_bazel() {
            println!("cargo:error=Bazel must be installed at version {} or greater. (Error: {})",
                     MIN_BAZEL,
                     e);
            process::exit(1);
        }
        let target_path = &TARGET.replace(":", "/");
        log_var!(target_path);
        if !Path::new(&source.join(".git")).exists() {
            run("git", |command| {
                command.arg("clone")
                    .arg(format!("--branch={}", TAG))
                    .arg("--recursive")
                    .arg(REPOSITORY)
                    .arg(&source)
            });
        }
        // Only configure if not previously configured.  Configuring runs a
        // `bazel clean`, which we don't want, because we want to be able to
        // continue from a cancelled build.
        let configure_hint_file_pb = source.join(".rust-configured");
        let configure_hint_file = Path::new(&configure_hint_file_pb);
        if !configure_hint_file.exists() {
            run("bash",
                |command| command.current_dir(&source)
                .env("TF_NEED_CUDA", if cfg!(feature = "tensorflow_gpu") {"1"} else {"0"})
                .arg("-c")
                .arg("yes ''|./configure"));
            File::create(configure_hint_file).unwrap();
        }
        run("bazel", |command| {
            command.current_dir(&source)
                .arg("build")
                .arg(format!("--jobs={}", get!("NUM_JOBS")))
                .arg("--compilation_mode=opt")
                .arg("--copt=-march=native")
                .arg(TARGET)
        });
        let target_bazel_bin = source.join("bazel-bin").join(target_path);
        log!("Copying {:?} to {:?}", target_bazel_bin, library_path);
        fs::copy(target_bazel_bin, library_path).unwrap();
    }

    println!("cargo:rustc-link-lib=dylib={}", LIBRARY);
    println!("cargo:rustc-link-search={}", lib_dir.display());
}

fn run<F>(name: &str, mut configure: F)
    where F: FnMut(&mut Command) -> &mut Command
{
    let mut command = Command::new(name);
    let configured = configure(&mut command);
    log!("Executing {:?}", configured);
    if !ok!(configured.status()).success() {
        panic!("failed to execute {:?}", configured);
    }
    log!("Command {:?} finished successfully", configured);
}

// Building TF 0.11.0rc1 with Bazel 0.3.0 gives this error when running `configure`:
//   expected ConfigurationTransition or NoneType for 'cfg' while calling label_list but got
// string instead:     data.
//       ERROR: com.google.devtools.build.lib.packages.BuildFileContainsErrorsException: error
// loading package '': Extension file 'tensorflow/tensorflow.bzl' has errors.
// And the simple solution is to require Bazel 0.3.1 or higher.
fn check_bazel() -> Result<(), Box<Error>> {
    let mut command = Command::new("bazel");
    command.arg("version");
    log!("Executing {:?}", command);
    let out = try!(command.output());
    log!("Command {:?} finished successfully", command);
    let stdout = try!(String::from_utf8(out.stdout));
    let mut found_version = false;
    for line in stdout.lines() {
        if line.starts_with("Build label:") {
            found_version = true;
            let mut version_str = line.split(":")
                .nth(1)
                .unwrap()
                .split(" ")
                .nth(1)
                .unwrap()
                .trim();
            if version_str.ends_with('-') {
                // hyphen is 1 byte long, so it's safe
                version_str = &version_str[..version_str.len() - 1];
            }
            let version = try!(Version::parse(version_str));
            let want = try!(Version::parse(MIN_BAZEL));
            if version < want {
                return Err(format!("Installed version {} is less than required version {}",
                                   version_str,
                                   MIN_BAZEL)
                    .into());
            }
        }
    }
    if !found_version {
        return Err("Did not find version number in `bazel version` output.".into());
    }
    Ok(())
}
<commit_msg>Use `log!()` macro to log build information in `tensorflow-sys/build.rs`<commit_after>extern crate curl;
extern crate flate2;
extern crate pkg_config;
extern crate semver;
extern crate tar;

use std::error::Error;
use std::fs::File;
use std::io::BufWriter;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use std::process::Command;
use std::{env, fs};

use curl::easy::Easy;
use flate2::read::GzDecoder;
use semver::Version;
use tar::Archive;

const LIBRARY: &'static str = "tensorflow";
const REPOSITORY: &'static str = "https://github.com/tensorflow/tensorflow.git";
const TARGET: &'static str = "tensorflow:libtensorflow.so";
// `VERSION` and `TAG` are separate because the tag is not always `'v' + VERSION`.
const VERSION: &'static str = "1.0.0";
const TAG: &'static str = "v1.0.0";
const MIN_BAZEL: &'static str = "0.3.2";

macro_rules! get(($name:expr) => (ok!(env::var($name))));
macro_rules! ok(($expression:expr) => ($expression.unwrap()));
macro_rules! log {
    ($fmt:expr) => (println!(concat!("libtensorflow-sys/build.rs:{}: ", $fmt), line!()));
    ($fmt:expr, $($arg:tt)*) => (println!(concat!("libtensorflow-sys/build.rs:{}: ", $fmt),
    line!(), $($arg)*));
}
macro_rules! log_var(($var:ident) => (log!(concat!(stringify!($var), " = {:?}"), $var)));

fn main() {
    if pkg_config::find_library(LIBRARY).is_ok() {
        log!("Returning early because {} was already found", LIBRARY);
        return;
    }

    let force_src = match env::var("TF_RUST_BUILD_FROM_SRC") {
        Ok(s) => s == "true",
        Err(_) => false,
    };
    if !force_src && env::consts::ARCH == "x86_64" && (env::consts::OS == "linux" || env::consts::OS == "macos") {
        install_prebuilt();
    } else {
        build_from_src();
    }
}

fn remove_suffix(value: &mut String, suffix: &str) {
    if value.ends_with(suffix) {
        let n = value.len();
        value.truncate(n - suffix.len());
    }
}

fn extract<P: AsRef<Path>, P2: AsRef<Path>>(archive_path: P, extract_to: P2) {
    let file = File::open(archive_path).unwrap();
    let unzipped = GzDecoder::new(file).unwrap();
    let mut a = Archive::new(unzipped);
    a.unpack(extract_to).unwrap();
}

// Downloads and unpacks a prebuilt binary. Only works for certain platforms.
fn install_prebuilt() {
    // Figure out the file names.
    let os = match env::consts::OS {
        "macos" => "darwin",
        x => x,
    };
    let proc_type = if cfg!(feature = "tensorflow_gpu") {"gpu"} else {"cpu"};
    let binary_url = format!(
        "https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-{}-{}-{}-{}.tar.gz",
        proc_type, os, env::consts::ARCH, VERSION);
    log_var!(binary_url);
    let short_file_name = binary_url.split("/").last().unwrap();
    let mut base_name = short_file_name.to_string();
    remove_suffix(&mut base_name, ".tar.gz");
    log_var!(base_name);
    let download_dir = match env::var("TF_RUST_DOWNLOAD_DIR") {
        Ok(s) => PathBuf::from(s),
        Err(_) => PathBuf::from(&get!("CARGO_MANIFEST_DIR")).join("target"),
    };
    if !download_dir.exists() {
        fs::create_dir(&download_dir).unwrap();
    }
    let file_name = download_dir.join(short_file_name);
    log_var!(file_name);

    // Download the tarball.
    if !file_name.exists() {
        let f = File::create(&file_name).unwrap();
        let mut writer = BufWriter::new(f);
        let mut easy = Easy::new();
        easy.url(&binary_url).unwrap();
        easy.write_function(move |data| {
            Ok(writer.write(data).unwrap())
        }).unwrap();
        easy.perform().unwrap();

        let response_code = easy.response_code().unwrap();
        if response_code != 200 {
            panic!("Unexpected response code {} for {}", response_code, binary_url);
        }
    }

    // Extract the tarball.
    let unpacked_dir = download_dir.join(base_name);
    let lib_dir = unpacked_dir.join("lib");
    let library_file = format!("lib{}.so", LIBRARY);
    let library_full_path = lib_dir.join(&library_file);
    if !library_full_path.exists() {
        extract(file_name, &unpacked_dir);
    }

    //run("find", |command| command); // TODO: remove
    run("ls", |command| {
        command.arg("-l").arg(lib_dir.to_str().unwrap())
        }); // TODO: remove

    println!("cargo:rustc-link-lib=dylib={}", LIBRARY);
    let output = PathBuf::from(&get!("OUT_DIR"));
    let new_library_full_path = output.join(&library_file);
    if new_library_full_path.exists() {
        log!("File {} already exists, deleting.", new_library_full_path.display());
        std::fs::remove_file(&new_library_full_path).unwrap();
    }

    log!("Copying {} to {}...", library_full_path.display(), new_library_full_path.display());
    std::fs::copy(&library_full_path, &new_library_full_path).unwrap();
    println!("cargo:rustc-link-search={}", output.display());
}

fn build_from_src() {
    let output = PathBuf::from(&get!("OUT_DIR"));
    log_var!(output);
    let source = PathBuf::from(&get!("CARGO_MANIFEST_DIR")).join(format!("target/source-{}", TAG));
    log_var!(source);
    let lib_dir = output.join(format!("lib-{}", TAG));
    log_var!(lib_dir);
    if lib_dir.exists() {
        log!("Directory {:?} already exists", lib_dir);
    } else {
        log!("Creating directory {:?}", lib_dir);
        fs::create_dir(lib_dir.clone()).unwrap();
    }
    let library_path = lib_dir.join(format!("lib{}.so", LIBRARY));
    log_var!(library_path);
    if library_path.exists() {
        log!("{:?} already exists, not building", library_path);
    } else {
        if let Err(e) = check_bazel() {
            println!("cargo:error=Bazel must be installed at version {} or greater. (Error: {})",
                     MIN_BAZEL,
                     e);
            process::exit(1);
        }
        let target_path = &TARGET.replace(":", "/");
        log_var!(target_path);
        if !Path::new(&source.join(".git")).exists() {
            run("git", |command| {
                command.arg("clone")
                    .arg(format!("--branch={}", TAG))
                    .arg("--recursive")
                    .arg(REPOSITORY)
                    .arg(&source)
            });
        }
        // Only configure if not previously configured.  Configuring runs a
        // `bazel clean`, which we don't want, because we want to be able to
        // continue from a cancelled build.
        let configure_hint_file_pb = source.join(".rust-configured");
        let configure_hint_file = Path::new(&configure_hint_file_pb);
        if !configure_hint_file.exists() {
            run("bash",
                |command| command.current_dir(&source)
                .env("TF_NEED_CUDA", if cfg!(feature = "tensorflow_gpu") {"1"} else {"0"})
                .arg("-c")
                .arg("yes ''|./configure"));
            File::create(configure_hint_file).unwrap();
        }
        run("bazel", |command| {
            command.current_dir(&source)
                .arg("build")
                .arg(format!("--jobs={}", get!("NUM_JOBS")))
                .arg("--compilation_mode=opt")
                .arg("--copt=-march=native")
                .arg(TARGET)
        });
        let target_bazel_bin = source.join("bazel-bin").join(target_path);
        log!("Copying {:?} to {:?}", target_bazel_bin, library_path);
        fs::copy(target_bazel_bin, library_path).unwrap();
    }

    println!("cargo:rustc-link-lib=dylib={}", LIBRARY);
    println!("cargo:rustc-link-search={}", lib_dir.display());
}

fn run<F>(name: &str, mut configure: F)
    where F: FnMut(&mut Command) -> &mut Command
{
    let mut command = Command::new(name);
    let configured = configure(&mut command);
    log!("Executing {:?}", configured);
    if !ok!(configured.status()).success() {
        panic!("failed to execute {:?}", configured);
    }
    log!("Command {:?} finished successfully", configured);
}

// Building TF 0.11.0rc1 with Bazel 0.3.0 gives this error when running `configure`:
//   expected ConfigurationTransition or NoneType for 'cfg' while calling label_list but got
// string instead:     data.
//       ERROR: com.google.devtools.build.lib.packages.BuildFileContainsErrorsException: error
// loading package '': Extension file 'tensorflow/tensorflow.bzl' has errors.
// And the simple solution is to require Bazel 0.3.1 or higher.
fn check_bazel() -> Result<(), Box<Error>> {
    let mut command = Command::new("bazel");
    command.arg("version");
    log!("Executing {:?}", command);
    let out = try!(command.output());
    log!("Command {:?} finished successfully", command);
    let stdout = try!(String::from_utf8(out.stdout));
    let mut found_version = false;
    for line in stdout.lines() {
        if line.starts_with("Build label:") {
            found_version = true;
            let mut version_str = line.split(":")
                .nth(1)
                .unwrap()
                .split(" ")
                .nth(1)
                .unwrap()
                .trim();
            if version_str.ends_with('-') {
                // hyphen is 1 byte long, so it's safe
                version_str = &version_str[..version_str.len() - 1];
            }
            let version = try!(Version::parse(version_str));
            let want = try!(Version::parse(MIN_BAZEL));
            if version < want {
                return Err(format!("Installed version {} is less than required version {}",
                                   version_str,
                                   MIN_BAZEL)
                    .into());
            }
        }
    }
    if !found_version {
        return Err("Did not find version number in `bazel version` output.".into());
    }
    Ok(())
}
<|endoftext|>


<commit_before>use util::bitfields;
use util::bits::Bits as _;

bitfields! {
    /// **4000000h - DISPCNT - LCD Control (Read/Write)**
    /// 0-2   BG Mode                (0-5=Video Mode 0-5, 6-7=Prohibited)
    /// 3     Reserved / CGB Mode    (0=GBA, 1=CGB; can be set only by BIOS opcodes)
    /// 4     Display Frame Select   (0-1=Frame 0-1) (for BG Modes 4,5 only)
    /// 5     H-Blank Interval Free  (1=Allow access to OAM during H-Blank)
    /// 6     OBJ Character VRAM Mapping (0=Two dimensional, 1=One dimensional)
    /// 7     Forced Blank           (1=Allow FAST access to VRAM,Palette,OAM)
    /// 8     Screen Display BG0  (0=Off, 1=On)
    /// 9     Screen Display BG1  (0=Off, 1=On)
    /// 10    Screen Display BG2  (0=Off, 1=On)
    /// 11    Screen Display BG3  (0=Off, 1=On)
    /// 12    Screen Display OBJ  (0=Off, 1=On)
    /// 13    Window 0 Display Flag   (0=Off, 1=On)
    /// 14    Window 1 Display Flag   (0=Off, 1=On)
    /// 15    OBJ Window Display Flag (0=Off, 1=On)
    pub struct LCDControl: u16 {
        [0,2]   bg_mode, set_bg_mode: u16,
        [3]     cgb_mode, set_cgb_mode: bool,
        [4]     frame, set_framae: u16,
        [5]     hblank_interval_free, set_hblank_interval_free: u16,
        [6]     obj_char_vram_mapping, set_obj_char_vram_mapping: ObjCharVramMapping,
        [7]     forced_blank, set_forced_blank: bool,
        [15]    obj_window_display, set_obj_window_display: bool,
    }
}

impl LCDControl {
    pub fn display_bg(&self, bg: u16) -> bool {
        if bg > 3 {
            return false;
        }
        self.value.is_bit_set(bg as u32 + 8)
    }

    pub fn display_obj(&self) -> bool {
        self.value.is_bit_set(12)
    }

    pub fn is_bitmap_mode(&self) -> bool {
        (3..6).contains(&self.bg_mode())
    }
}

bitfields! {
    /// **4000004h - DISPSTAT - General LCD Status (Read/Write)**
    /// Display status and Interrupt control. The H-Blank conditions are generated once per scanline, including for the 'hidden' scanlines during V-Blank.
    /// Bit   Expl.
    /// 0     V-Blank flag   (Read only) (1=VBlank) (set in line 160..226; not 227)
    /// 1     H-Blank flag   (Read only) (1=HBlank) (toggled in all lines, 0..227)
    /// 2     V-Counter flag (Read only) (1=Match)  (set in selected line)     (R)
    /// 3     V-Blank IRQ Enable         (1=Enable)                          (R/W)
    /// 4     H-Blank IRQ Enable         (1=Enable)                          (R/W)
    /// 5     V-Counter IRQ Enable       (1=Enable)                          (R/W)
    /// 6     Not used (0) / DSi: LCD Initialization Ready (0=Busy, 1=Ready)   (R)
    /// 7     Not used (0) / NDS: MSB of V-Vcount Setting (LYC.Bit8) (0..262)(R/W)
    /// 8-15  V-Count Setting (LYC)      (0..227)                            (R/W)
    pub struct LCDStatus: u16 {
        [0]     vblank, set_vblank: bool,
        [1]     hblank, set_hblank: bool,
        [2]     vcounter_match, set_vcounter_match: bool,
        [3]     vblank_irq_enable, set_vblank_irq_enable: bool,
        [4]     hblank_irq_enable, set_hblank_irq_enable: bool,
        [5]     vcounter_irq_enable, set_vcounter_irq_enable: bool,
        [8,15]  vcount_setting, set_vcount_setting: u16,

        readonly = 0x0047,
    }
}

bitfields! {
    /// **4000008h - BG0CNT - BG0 Control (R/W) (BG Modes 0,1 only)**
    /// **400000Ah - BG1CNT - BG1 Control (R/W) (BG Modes 0,1 only)**
    /// **400000Ch - BG2CNT - BG2 Control (R/W) (BG Modes 0,1,2 only)**
    /// **400000Eh - BG3CNT - BG3 Control (R/W) (BG Modes 0,2 only)**
    ///   Bit   Expl.
    ///   0-1   BG Priority           (0-3, 0=Highest)
    ///   2-3   Character Base Block  (0-3, in units of 16 KBytes) (=BG Tile Data)
    ///   4-5   Not used (must be zero) (except in NDS mode: MSBs of char base)
    ///   6     Mosaic                (0=Disable, 1=Enable)
    ///   7     Colors/Palettes       (0=16/16, 1=256/1)
    ///   8-12  Screen Base Block     (0-31, in units of 2 KBytes) (=BG Map Data)
    ///   13    BG0/BG1: Not used (except in NDS mode: Ext Palette Slot for BG0/BG1)
    ///   13    BG2/BG3: Display Area Overflow (0=Transparent, 1=Wraparound)
    ///   14-15 Screen Size (0-3)
    /// Internal Screen Size (dots) and size of BG Map (bytes):
    ///   Value  Text Mode      Rotation/Scaling Mode
    ///   0      256x256 (2K)   128x128   (256 bytes)
    ///   1      512x256 (4K)   256x256   (1K)
    ///   2      256x512 (4K)   512x512   (4K)
    ///   3      512x512 (8K)   1024x1024 (16K)
    /// In case that some or all BGs are set to same priority then BG0 is having the highest, and BG3 the lowest priority.
    pub struct BgControl: u16 {
        [0,1]   priority, set_priority: u16,
        [6]     mosaic, set_mosaic: bool,
        [7]     palette_256, set_palette_256: bool,
        [13]    wraparound, set_wraparound: bool,
        [14,15] screen_size, set_screen_size: ScreenSize,
    }
}

impl BgControl {
    /// Returns the character base block offset in bytes.
    pub fn character_base(&self) -> u32 {
        self.value.bits(2, 3) as u32 * 0x4000
    }

    /// Sets the character base block offset. Must be an increment of 16KiB less than or equal to 48KB.
    pub fn set_character_base(&mut self, offset: u32) {
        debug_assert!(offset & 0x3FFF == 0, "offset must be an increment of 16KiB");
        debug_assert!(offset <= 0xC000, "offset must be less than 48KiB");
        let block = offset / 0x4000;
        self.value = self.value.replace_bits(2, 3, block as u16);
    }

    /// Returns the screen base block offset in bytes.
    pub fn screen_base(&self) -> u32 {
        self.value.bits(8, 12) as u32 * 0x800
    }

    /// Sets the screen base block offset. Must be an increment of 2KiB less than or equal to 62KiB.
    pub fn set_screen_base(&mut self, offset: u32) {
        debug_assert!(offset & 0x7FF == 0, "offset must be an increment of 2KiB");
        debug_assert!(offset <= 0xF800, "offset must be less than 62KiB");
        let block = offset / 0x800;
        self.value = self.value.replace_bits(8, 12, block as u16);
    }
}

bitfields! {
    pub struct BgOffset: u32 {
        [0,8]   x, set_x: u16,
        [16,24] y, set_y: u16,
    }
}

bitfields! {
    /// 4000050h - BLDCNT - Color Special Effects Selection (R/W)
    ///   Bit   Expl.
    ///   0     BG0 1st Target Pixel (Background 0)
    ///   1     BG1 1st Target Pixel (Background 1)
    ///   2     BG2 1st Target Pixel (Background 2)
    ///   3     BG3 1st Target Pixel (Background 3)
    ///   4     OBJ 1st Target Pixel (Top-most OBJ pixel)
    ///   5     BD  1st Target Pixel (Backdrop)
    ///   6-7   Color Special Effect (0-3, see below)
    ///          0 = None                (Special effects disabled)
    ///          1 = Alpha Blending      (1st+2nd Target mixed)
    ///          2 = Brightness Increase (1st Target becomes whiter)
    ///          3 = Brightness Decrease (1st Target becomes blacker)
    ///   8     BG0 2nd Target Pixel (Background 0)
    ///   9     BG1 2nd Target Pixel (Background 1)
    ///   10    BG2 2nd Target Pixel (Background 2)
    ///   11    BG3 2nd Target Pixel (Background 3)
    ///   12    OBJ 2nd Target Pixel (Top-most OBJ pixel)
    ///   13    BD  2nd Target Pixel (Backdrop)
    ///   14-15 Not used
    pub struct ColorSpecialEffects: u16 {
        [6,7]   effect, set_effect: Effect,
    }
}

impl ColorSpecialEffects {
    pub fn is_first_target(&self, layer: usize) -> bool {
        if layer > 5 {
            return false;
        }
        self.value.is_bit_set(layer as _)
    }

    pub fn is_second_target(&self, layer: usize) -> bool {
        if layer > 5 {
            return false;
        }
        self.value.is_bit_set((layer + 8) as _)
    }
}

bitfields! {
    /// 4000052h - BLDALPHA - Alpha Blending Coefficients (R/W) (not W)
    /// Used for Color Special Effects Mode 1, and for Semi-Transparent OBJs.
    ///   Bit   Expl.
    ///   0-4   EVA Coefficient (1st Target) (0..16 = 0/16..16/16, 17..31=16/16)
    ///   5-7   Not used
    ///   8-12  EVB Coefficient (2nd Target) (0..16 = 0/16..16/16, 17..31=16/16)
    ///   13-15 Not used
    pub struct AlphaBlendingCoeff: u16 {}
}

impl AlphaBlendingCoeff {
    pub fn eva_coeff(&self) -> u16 {
        self.value.bits(0, 4).min(16)
    }

    pub fn evb_coeff(&self) -> u16 {
        self.value.bits(8, 12).min(16)
    }

    pub fn set_eva_coeff(&mut self, eva_coeff: u16) {
        self.value = self.value.replace_bits(0, 4, eva_coeff.min(16));
    }

    pub fn set_evb(&mut self, evb_coeff: u16) {
        self.value = self.value.replace_bits(8, 12, evb_coeff.min(16));
    }
}

bitfields! {
    pub struct WaitstateControl: u16 {
        readonly = 0x8000
    }
}

util::primitive_enum! {
    pub enum Effect: u16 {
        None = 0,
        AlphaBlending,
        BrightnessIncrease,
        BrightnessDecrease,
    }
}

util::primitive_enum! {
    pub enum ObjCharVramMapping: u16 {
        TwoDimensional = 0,
        OneDimensional,
    }
}

pub struct ScreenSize(u8);

impl ScreenSize {
    pub fn width(&self, rotscale: bool) -> u32 {
        //   Value  Text Mode  Rotation/Scaling Mode
        //   0      256        128
        //   1      512        256
        //   2      256        512
        //   3      512        1024

        if !rotscale {
            ((self.0 as u32 + 1) << 1) * 256
        } else {
            128 << (self.0 as u32)
        }
    }

    pub fn height(&self, rotscale: bool) -> u32 {
        //   Value  Text Mode  Rotation/Scaling Mode
        //   0      256        128
        //   1      256        256
        //   2      512        512
        //   3      512        1024
        if !rotscale {
            256 << ((self.0 as u32 & 0x2) >> 1)
        } else {
            128 << (self.0 as u32)
        }
    }
}

impl From<u16> for ScreenSize {
    fn from(primitive: u16) -> ScreenSize {
        ScreenSize(primitive as u8)
    }
}

impl From<ScreenSize> for u16 {
    fn from(size: ScreenSize) -> u16 {
        size.0 as u16
    }
}
<commit_msg>Fix type for LCDControl::hblank_interval_free.<commit_after>use util::bitfields;
use util::bits::Bits as _;

bitfields! {
    /// **4000000h - DISPCNT - LCD Control (Read/Write)**
    /// 0-2   BG Mode                (0-5=Video Mode 0-5, 6-7=Prohibited)
    /// 3     Reserved / CGB Mode    (0=GBA, 1=CGB; can be set only by BIOS opcodes)
    /// 4     Display Frame Select   (0-1=Frame 0-1) (for BG Modes 4,5 only)
    /// 5     H-Blank Interval Free  (1=Allow access to OAM during H-Blank)
    /// 6     OBJ Character VRAM Mapping (0=Two dimensional, 1=One dimensional)
    /// 7     Forced Blank           (1=Allow FAST access to VRAM,Palette,OAM)
    /// 8     Screen Display BG0  (0=Off, 1=On)
    /// 9     Screen Display BG1  (0=Off, 1=On)
    /// 10    Screen Display BG2  (0=Off, 1=On)
    /// 11    Screen Display BG3  (0=Off, 1=On)
    /// 12    Screen Display OBJ  (0=Off, 1=On)
    /// 13    Window 0 Display Flag   (0=Off, 1=On)
    /// 14    Window 1 Display Flag   (0=Off, 1=On)
    /// 15    OBJ Window Display Flag (0=Off, 1=On)
    pub struct LCDControl: u16 {
        [0,2]   bg_mode, set_bg_mode: u16,
        [3]     cgb_mode, set_cgb_mode: bool,
        [4]     frame, set_framae: u16,
        [5]     hblank_interval_free, set_hblank_interval_free: bool,
        [6]     obj_char_vram_mapping, set_obj_char_vram_mapping: ObjCharVramMapping,
        [7]     forced_blank, set_forced_blank: bool,
        [15]    obj_window_display, set_obj_window_display: bool,
    }
}

impl LCDControl {
    pub fn display_bg(&self, bg: u16) -> bool {
        if bg > 3 {
            return false;
        }
        self.value.is_bit_set(bg as u32 + 8)
    }

    pub fn display_obj(&self) -> bool {
        self.value.is_bit_set(12)
    }

    pub fn is_bitmap_mode(&self) -> bool {
        (3..6).contains(&self.bg_mode())
    }
}

bitfields! {
    /// **4000004h - DISPSTAT - General LCD Status (Read/Write)**
    /// Display status and Interrupt control. The H-Blank conditions are generated once per scanline, including for the 'hidden' scanlines during V-Blank.
    /// Bit   Expl.
    /// 0     V-Blank flag   (Read only) (1=VBlank) (set in line 160..226; not 227)
    /// 1     H-Blank flag   (Read only) (1=HBlank) (toggled in all lines, 0..227)
    /// 2     V-Counter flag (Read only) (1=Match)  (set in selected line)     (R)
    /// 3     V-Blank IRQ Enable         (1=Enable)                          (R/W)
    /// 4     H-Blank IRQ Enable         (1=Enable)                          (R/W)
    /// 5     V-Counter IRQ Enable       (1=Enable)                          (R/W)
    /// 6     Not used (0) / DSi: LCD Initialization Ready (0=Busy, 1=Ready)   (R)
    /// 7     Not used (0) / NDS: MSB of V-Vcount Setting (LYC.Bit8) (0..262)(R/W)
    /// 8-15  V-Count Setting (LYC)      (0..227)                            (R/W)
    pub struct LCDStatus: u16 {
        [0]     vblank, set_vblank: bool,
        [1]     hblank, set_hblank: bool,
        [2]     vcounter_match, set_vcounter_match: bool,
        [3]     vblank_irq_enable, set_vblank_irq_enable: bool,
        [4]     hblank_irq_enable, set_hblank_irq_enable: bool,
        [5]     vcounter_irq_enable, set_vcounter_irq_enable: bool,
        [8,15]  vcount_setting, set_vcount_setting: u16,

        readonly = 0x0047,
    }
}

bitfields! {
    /// **4000008h - BG0CNT - BG0 Control (R/W) (BG Modes 0,1 only)**
    /// **400000Ah - BG1CNT - BG1 Control (R/W) (BG Modes 0,1 only)**
    /// **400000Ch - BG2CNT - BG2 Control (R/W) (BG Modes 0,1,2 only)**
    /// **400000Eh - BG3CNT - BG3 Control (R/W) (BG Modes 0,2 only)**
    ///   Bit   Expl.
    ///   0-1   BG Priority           (0-3, 0=Highest)
    ///   2-3   Character Base Block  (0-3, in units of 16 KBytes) (=BG Tile Data)
    ///   4-5   Not used (must be zero) (except in NDS mode: MSBs of char base)
    ///   6     Mosaic                (0=Disable, 1=Enable)
    ///   7     Colors/Palettes       (0=16/16, 1=256/1)
    ///   8-12  Screen Base Block     (0-31, in units of 2 KBytes) (=BG Map Data)
    ///   13    BG0/BG1: Not used (except in NDS mode: Ext Palette Slot for BG0/BG1)
    ///   13    BG2/BG3: Display Area Overflow (0=Transparent, 1=Wraparound)
    ///   14-15 Screen Size (0-3)
    /// Internal Screen Size (dots) and size of BG Map (bytes):
    ///   Value  Text Mode      Rotation/Scaling Mode
    ///   0      256x256 (2K)   128x128   (256 bytes)
    ///   1      512x256 (4K)   256x256   (1K)
    ///   2      256x512 (4K)   512x512   (4K)
    ///   3      512x512 (8K)   1024x1024 (16K)
    /// In case that some or all BGs are set to same priority then BG0 is having the highest, and BG3 the lowest priority.
    pub struct BgControl: u16 {
        [0,1]   priority, set_priority: u16,
        [6]     mosaic, set_mosaic: bool,
        [7]     palette_256, set_palette_256: bool,
        [13]    wraparound, set_wraparound: bool,
        [14,15] screen_size, set_screen_size: ScreenSize,
    }
}

impl BgControl {
    /// Returns the character base block offset in bytes.
    pub fn character_base(&self) -> u32 {
        self.value.bits(2, 3) as u32 * 0x4000
    }

    /// Sets the character base block offset. Must be an increment of 16KiB less than or equal to 48KB.
    pub fn set_character_base(&mut self, offset: u32) {
        debug_assert!(offset & 0x3FFF == 0, "offset must be an increment of 16KiB");
        debug_assert!(offset <= 0xC000, "offset must be less than 48KiB");
        let block = offset / 0x4000;
        self.value = self.value.replace_bits(2, 3, block as u16);
    }

    /// Returns the screen base block offset in bytes.
    pub fn screen_base(&self) -> u32 {
        self.value.bits(8, 12) as u32 * 0x800
    }

    /// Sets the screen base block offset. Must be an increment of 2KiB less than or equal to 62KiB.
    pub fn set_screen_base(&mut self, offset: u32) {
        debug_assert!(offset & 0x7FF == 0, "offset must be an increment of 2KiB");
        debug_assert!(offset <= 0xF800, "offset must be less than 62KiB");
        let block = offset / 0x800;
        self.value = self.value.replace_bits(8, 12, block as u16);
    }
}

bitfields! {
    pub struct BgOffset: u32 {
        [0,8]   x, set_x: u16,
        [16,24] y, set_y: u16,
    }
}

bitfields! {
    /// 4000050h - BLDCNT - Color Special Effects Selection (R/W)
    ///   Bit   Expl.
    ///   0     BG0 1st Target Pixel (Background 0)
    ///   1     BG1 1st Target Pixel (Background 1)
    ///   2     BG2 1st Target Pixel (Background 2)
    ///   3     BG3 1st Target Pixel (Background 3)
    ///   4     OBJ 1st Target Pixel (Top-most OBJ pixel)
    ///   5     BD  1st Target Pixel (Backdrop)
    ///   6-7   Color Special Effect (0-3, see below)
    ///          0 = None                (Special effects disabled)
    ///          1 = Alpha Blending      (1st+2nd Target mixed)
    ///          2 = Brightness Increase (1st Target becomes whiter)
    ///          3 = Brightness Decrease (1st Target becomes blacker)
    ///   8     BG0 2nd Target Pixel (Background 0)
    ///   9     BG1 2nd Target Pixel (Background 1)
    ///   10    BG2 2nd Target Pixel (Background 2)
    ///   11    BG3 2nd Target Pixel (Background 3)
    ///   12    OBJ 2nd Target Pixel (Top-most OBJ pixel)
    ///   13    BD  2nd Target Pixel (Backdrop)
    ///   14-15 Not used
    pub struct ColorSpecialEffects: u16 {
        [6,7]   effect, set_effect: Effect,
    }
}

impl ColorSpecialEffects {
    pub fn is_first_target(&self, layer: usize) -> bool {
        if layer > 5 {
            return false;
        }
        self.value.is_bit_set(layer as _)
    }

    pub fn is_second_target(&self, layer: usize) -> bool {
        if layer > 5 {
            return false;
        }
        self.value.is_bit_set((layer + 8) as _)
    }
}

bitfields! {
    /// 4000052h - BLDALPHA - Alpha Blending Coefficients (R/W) (not W)
    /// Used for Color Special Effects Mode 1, and for Semi-Transparent OBJs.
    ///   Bit   Expl.
    ///   0-4   EVA Coefficient (1st Target) (0..16 = 0/16..16/16, 17..31=16/16)
    ///   5-7   Not used
    ///   8-12  EVB Coefficient (2nd Target) (0..16 = 0/16..16/16, 17..31=16/16)
    ///   13-15 Not used
    pub struct AlphaBlendingCoeff: u16 {}
}

impl AlphaBlendingCoeff {
    pub fn eva_coeff(&self) -> u16 {
        self.value.bits(0, 4).min(16)
    }

    pub fn evb_coeff(&self) -> u16 {
        self.value.bits(8, 12).min(16)
    }

    pub fn set_eva_coeff(&mut self, eva_coeff: u16) {
        self.value = self.value.replace_bits(0, 4, eva_coeff.min(16));
    }

    pub fn set_evb(&mut self, evb_coeff: u16) {
        self.value = self.value.replace_bits(8, 12, evb_coeff.min(16));
    }
}

bitfields! {
    pub struct WaitstateControl: u16 {
        readonly = 0x8000
    }
}

util::primitive_enum! {
    pub enum Effect: u16 {
        None = 0,
        AlphaBlending,
        BrightnessIncrease,
        BrightnessDecrease,
    }
}

util::primitive_enum! {
    pub enum ObjCharVramMapping: u16 {
        TwoDimensional = 0,
        OneDimensional,
    }
}

pub struct ScreenSize(u8);

impl ScreenSize {
    pub fn width(&self, rotscale: bool) -> u32 {
        //   Value  Text Mode  Rotation/Scaling Mode
        //   0      256        128
        //   1      512        256
        //   2      256        512
        //   3      512        1024

        if !rotscale {
            ((self.0 as u32 + 1) << 1) * 256
        } else {
            128 << (self.0 as u32)
        }
    }

    pub fn height(&self, rotscale: bool) -> u32 {
        //   Value  Text Mode  Rotation/Scaling Mode
        //   0      256        128
        //   1      256        256
        //   2      512        512
        //   3      512        1024
        if !rotscale {
            256 << ((self.0 as u32 & 0x2) >> 1)
        } else {
            128 << (self.0 as u32)
        }
    }
}

impl From<u16> for ScreenSize {
    fn from(primitive: u16) -> ScreenSize {
        ScreenSize(primitive as u8)
    }
}

impl From<ScreenSize> for u16 {
    fn from(size: ScreenSize) -> u16 {
        size.0 as u16
    }
}
<|endoftext|>


<commit_before>
pub fn from_hex(hex_in: &str) -> Vec<u8>
{
    let mut bin_out = Vec::new();

    let mut combined = 0u8;
    let mut second_byte = false;
    for c in hex_in.bytes() {
        let nibble = (c & 0x0f) + ((c & 0x40) >> 6) * 9;

        if second_byte {
            combined += nibble;
            second_byte = false;

            bin_out.push(combined);
        } else {
            combined = nibble << 4;
            second_byte = true;
        }
    }

    return bin_out;
}

fn encode_single_base64(byte_in: u8) -> char {
    match byte_in {
        0...25 => (65u8 + byte_in) as char,
        26...51 => (71u8 + byte_in) as char,
        52...61 => (byte_in - 4u8) as char,
        62 => '+',
        63 => '/',
        _ => ' ' // FIXME: error
    }
}

pub fn to_base64(bin_in: &[u8]) -> String {
    let mut result = String::new();

    let mut i = 0u;
    let total = bin_in.len();
    while i < total {
        // combine three bytes
        let mut current = bin_in[i] as u32 << 16;
        let mut fill_bytes = 0u;
        current += if i+1 < total { bin_in[i+1] as u32 << 8 } else { fill_bytes +=1; 0 };
        current += if i+2 < total { bin_in[i+2] as u32 } else { fill_bytes +=1; 0 };

        // encode
        result.push(encode_single_base64(((current & 0x00fc0000) >> 18) as u8));
        result.push(encode_single_base64(((current & 0x0003f000) >> 12) as u8));
        result.push(if fill_bytes < 2 { encode_single_base64(((current & 0x00000fc0) >> 6) as u8) } else { '=' });
        result.push(if fill_bytes < 1 { encode_single_base64((current & 0x0000003f) as u8 ) } else { '=' });

        i += 3;
    }

    result
}

#[test]
fn from_hex_basics() {
    assert_eq!(from_hex(""), vec![]);
    assert_eq!(from_hex("01"), vec![1]);
    assert_eq!(from_hex("ff"), vec![255]);
    assert_eq!(from_hex("A0"), vec![160]);
    assert_eq!(from_hex("A00AFf"), vec![160, 10, 255]);
}

#[test]
fn to_base64_rfc4648() {
   assert_eq!(to_base64([]), String::from_str(""));// ""
   assert_eq!(to_base64("f".as_bytes()), String::from_str("Zg=="));
   assert_eq!(to_base64("fo".as_bytes()), String::from_str("Zm8="));
   assert_eq!(to_base64("foo".as_bytes()), String::from_str("Zm9v"));
   assert_eq!(to_base64("foob".as_bytes()), String::from_str("Zm9vYg=="));
   assert_eq!(to_base64("fooba".as_bytes()), String::from_str("Zm9vYmE="));
   assert_eq!(to_base64("foobar".as_bytes()), String::from_str("Zm9vYmFy"));
}

#[test]
fn challenge1() {
    let input = "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d";
    let output = to_base64( &*from_hex(input) );
    assert_eq!(output, String::from_str("SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t"));
}
<commit_msg>Make encode_single_base64 use Option<commit_after>
pub fn from_hex(hex_in: &str) -> Vec<u8>
{
    let mut bin_out = Vec::new();

    let mut combined = 0u8;
    let mut second_byte = false;
    for c in hex_in.bytes() {
        let nibble = (c & 0x0f) + ((c & 0x40) >> 6) * 9;

        if second_byte {
            combined += nibble;
            second_byte = false;

            bin_out.push(combined);
        } else {
            combined = nibble << 4;
            second_byte = true;
        }
    }

    return bin_out;
}

fn encode_single_base64(byte_in: u8) -> Option<char> {
    match byte_in {
        0...25 => Some((65u8 + byte_in) as char),
        26...51 => Some((71u8 + byte_in) as char),
        52...61 => Some((byte_in - 4u8) as char),
        62 => Some('+'),
        63 => Some('/'),
        _ => None
    }
}

pub fn to_base64(bin_in: &[u8]) -> String {
    let mut result = String::new();

    let mut i = 0u;
    let total = bin_in.len();
    while i < total {
        // combine three bytes
        let mut current = bin_in[i] as u32 << 16;
        let mut fill_bytes = 0u;
        current += if i+1 < total { bin_in[i+1] as u32 << 8 } else { fill_bytes +=1; 0 };
        current += if i+2 < total { bin_in[i+2] as u32 } else { fill_bytes +=1; 0 };

        // encode
        result.push(encode_single_base64(((current & 0x00fc0000) >> 18) as u8).unwrap());
        result.push(encode_single_base64(((current & 0x0003f000) >> 12) as u8).unwrap());
        result.push(if fill_bytes < 2 { encode_single_base64(((current & 0x00000fc0) >> 6) as u8).unwrap() } else { '=' });
        result.push(if fill_bytes < 1 { encode_single_base64((current & 0x0000003f) as u8 ).unwrap() } else { '=' });

        i += 3;
    }

    result
}

#[test]
fn encode_single_base64_basics() {
    assert_eq!(encode_single_base64(0), Some('A'));
    assert_eq!(encode_single_base64(27), Some('b'));
    assert_eq!(encode_single_base64(61), Some('9'));
    assert_eq!(encode_single_base64(63), Some('/'));
}

#[test]
fn encode_single_base64_fail() {
    assert_eq!(encode_single_base64(64), None);
    assert_eq!(encode_single_base64(255), None);
}

#[test]
fn from_hex_basics() {
    assert_eq!(from_hex(""), vec![]);
    assert_eq!(from_hex("01"), vec![1]);
    assert_eq!(from_hex("ff"), vec![255]);
    assert_eq!(from_hex("A0"), vec![160]);
    assert_eq!(from_hex("A00AFf"), vec![160, 10, 255]);
}

#[test]
fn to_base64_rfc4648() {
   assert_eq!(to_base64([]), String::from_str(""));// ""
   assert_eq!(to_base64("f".as_bytes()), String::from_str("Zg=="));
   assert_eq!(to_base64("fo".as_bytes()), String::from_str("Zm8="));
   assert_eq!(to_base64("foo".as_bytes()), String::from_str("Zm9v"));
   assert_eq!(to_base64("foob".as_bytes()), String::from_str("Zm9vYg=="));
   assert_eq!(to_base64("fooba".as_bytes()), String::from_str("Zm9vYmE="));
   assert_eq!(to_base64("foobar".as_bytes()), String::from_str("Zm9vYmFy"));
}

#[test]
fn challenge1() {
    let input = "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d";
    let output = to_base64( &*from_hex(input) );
    assert_eq!(output, String::from_str("SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t"));
}
<|endoftext|>


<commit_before>use board::sjadam_board::SjadamBoard;
use uci::UciBoard;
use board::sjadam_move::SjadamMove;
use board::std_board::*;
use search_algorithms::game_move::Move;
use search_algorithms::board::{GameResult, EvalBoard};
use tests::move_gen_tests;

#[test]
fn correct_move_gen_start_pos() {
    let start_board = SjadamBoard::start_board().clone();
    let moves = start_board.all_legal_moves();
    assert_eq!(moves.len(), 146, "Found {} moves: {:?}, expected 146",
               moves.len(), moves);
}

/// Tests whether a pawn is allowed to sjadam over an opponent pawn
#[test]
fn jump_over_opponent() {
    let board = SjadamBoard::from_fen("8/8/8/7p/7P/8/8/K1k5 w - - 1 1").unwrap();
    assert_eq!(board.game_result(), None);
    let moves = board.all_legal_moves();
    assert_eq!(board.all_legal_moves().len(), 5,
               "Expected 5 legal moves, found {} moves: {:?}\n{:?}",
               moves.len(), moves, board);
}

#[test]
fn no_stalemate_test() {
    let board = SjadamBoard::from_fen("8/8/8/5p1k/3p1Q2/3P2R1/P3p2P/4K3 b - - 2 39").unwrap();
    assert_eq!(board.game_result(), None);
    let moves = board.all_legal_moves();
    // The exact number may be wrong due to other bugs
    // So don't trust this test
    assert_eq!(board.all_legal_moves().len(), 13,
               "Expected 13 legal moves, found {} moves: {:?}\n{:?}",
               moves.len(), moves, board);
}

#[test]
fn can_take_king_while_checked() {
    let board = SjadamBoard::from_fen("r2q2n1/pp4pp/6k1/2Nb4/8/5P2/P1P1PK2/2B3q1 w - - 0 1").unwrap();
    // Black is really sjadammated, so this is also a possible outcome
    if board.game_result() != Some(GameResult::WhiteWin) {
        let moves = board.all_legal_moves();

        let correct_move = SjadamMove {
            from: Square::from_alg("c5").unwrap(),
            sjadam_square: Square::from_alg("e5").unwrap(),
            to: Square::from_alg("g6").unwrap(),
            prom: false } ;
        assert!(board.all_legal_moves().contains(&correct_move),
                "White couldn't take king on board:\n{:?}Moves: {:?}",
                board, moves);
    }
}

#[test]
fn sjadam_move_to_promote_pawn() {
    let board = SjadamBoard::from_fen("k7/5R2/5P2/8/8/8/8/7K w - - 0 1").unwrap();
    let moves = board.all_legal_moves();

    let correct_move = SjadamMove::from_alg("f6f8-").unwrap();
    assert!(board.all_legal_moves().contains(&correct_move),
            "White couldn't promote in sjadam on board:\n{:?}Moves: {:?}",
            board, moves);
}

#[test]
fn no_moves_on_back_rank() {
    let board = SjadamBoard::from_fen("8/K7/P7/8/8/8/8/7k w - - 0 1").unwrap();
    let moves = board.all_legal_moves();
    assert_eq!(moves.len(), 9, "Expected to find {} moves, found {}: {:?}", 9, moves.len(), moves);
}

#[test]
fn startpos_perf_test() {
    let mut board = SjadamBoard::start_board();
    for (n, &moves) in (1..4).zip([146, 21_469, 3_268_163].iter()) {
        assert_eq!(move_gen_tests::legal_moves_after_plies(&mut board, n), moves);
    }
}

#[test]
fn castling_en_passant_perf_test() {
    let mut board = SjadamBoard::start_board();
    board.do_move(SjadamMove::from_alg("g1e3-").unwrap());
    board.do_move(SjadamMove::from_alg("g8e6-").unwrap());
    board.do_move(SjadamMove::from_alg("f1d3d3c4").unwrap());
    board.do_move(SjadamMove::from_alg("e8g8-").unwrap());
    board.do_move(SjadamMove::from_alg("-c2c3").unwrap());
    board.do_move(SjadamMove::from_alg("-d7d5").unwrap());
    board.do_move(SjadamMove::from_alg("c1a3-").unwrap());
    board.do_move(SjadamMove::from_alg("-b7b5").unwrap());
    for (n, &moves) in (1..4).zip([160, 26_959, 4_259_956].iter()) {
        let result = move_gen_tests::legal_moves_after_plies(&mut board, n);
        assert_eq!(result, moves,
                   "Expected {} moves, found {} on board:\n{:?}.", moves, result, board);
    }
}
<commit_msg>Sjadam move gen tests no longer rely on internal move structure<commit_after>use board::sjadam_board::SjadamBoard;
use uci::UciBoard;
use board::sjadam_move::SjadamMove;
use search_algorithms::game_move::Move;
use search_algorithms::board::{GameResult, EvalBoard};
use tests::move_gen_tests;

#[test]
fn correct_move_gen_start_pos() {
    let start_board = SjadamBoard::start_board().clone();
    let moves = start_board.all_legal_moves();
    assert_eq!(moves.len(), 146, "Found {} moves: {:?}, expected 146",
               moves.len(), moves);
}

/// Tests whether a pawn is allowed to sjadam over an opponent pawn
#[test]
fn jump_over_opponent() {
    let board = SjadamBoard::from_fen("8/8/8/7p/7P/8/8/K1k5 w - - 1 1").unwrap();
    assert_eq!(board.game_result(), None);
    let moves = board.all_legal_moves();
    assert_eq!(board.all_legal_moves().len(), 5,
               "Expected 5 legal moves, found {} moves: {:?}\n{:?}",
               moves.len(), moves, board);
}

#[test]
fn no_stalemate_test() {
    let board = SjadamBoard::from_fen("8/8/8/5p1k/3p1Q2/3P2R1/P3p2P/4K3 b - - 2 39").unwrap();
    assert_eq!(board.game_result(), None);
    let moves = board.all_legal_moves();
    // The exact number may be wrong due to other bugs
    // So don't trust this test
    assert_eq!(board.all_legal_moves().len(), 13,
               "Expected 13 legal moves, found {} moves: {:?}\n{:?}",
               moves.len(), moves, board);
}

#[test]
fn can_take_king_while_checked() {
    let board = SjadamBoard::from_fen("r2q2n1/pp4pp/6k1/2Nb4/8/5P2/P1P1PK2/2B3q1 w - - 0 1").unwrap();
    // Black is really sjadammated, so this is also a possible outcome
    if board.game_result() != Some(GameResult::WhiteWin) {
        let moves = board.all_legal_moves();

        let correct_move = SjadamMove::from_alg("c5e5e5g6").unwrap();
        assert!(board.all_legal_moves().contains(&correct_move),
                "White couldn't take king on board:\n{:?}Moves: {:?}",
                board, moves);
    }
}

#[test]
fn sjadam_move_to_promote_pawn() {
    let board = SjadamBoard::from_fen("k7/5R2/5P2/8/8/8/8/7K w - - 0 1").unwrap();
    let moves = board.all_legal_moves();

    let correct_move = SjadamMove::from_alg("f6f8-").unwrap();
    assert!(board.all_legal_moves().contains(&correct_move),
            "White couldn't promote in sjadam on board:\n{:?}Moves: {:?}",
            board, moves);
}

#[test]
fn no_moves_on_back_rank() {
    let board = SjadamBoard::from_fen("8/K7/P7/8/8/8/8/7k w - - 0 1").unwrap();
    let moves = board.all_legal_moves();
    assert_eq!(moves.len(), 9, "Expected to find {} moves, found {}: {:?}", 9, moves.len(), moves);
}

#[test]
fn startpos_perf_test() {
    let mut board = SjadamBoard::start_board();
    for (n, &moves) in (1..4).zip([146, 21_469, 3_268_163].iter()) {
        assert_eq!(move_gen_tests::legal_moves_after_plies(&mut board, n), moves);
    }
}

#[test]
fn castling_en_passant_perf_test() {
    let mut board = SjadamBoard::start_board();
    board.do_move(SjadamMove::from_alg("g1e3-").unwrap());
    board.do_move(SjadamMove::from_alg("g8e6-").unwrap());
    board.do_move(SjadamMove::from_alg("f1d3d3c4").unwrap());
    board.do_move(SjadamMove::from_alg("e8g8-").unwrap());
    board.do_move(SjadamMove::from_alg("-c2c3").unwrap());
    board.do_move(SjadamMove::from_alg("-d7d5").unwrap());
    board.do_move(SjadamMove::from_alg("c1a3-").unwrap());
    board.do_move(SjadamMove::from_alg("-b7b5").unwrap());
    for (n, &moves) in (1..4).zip([160, 26_959, 4_259_956].iter()) {
        let result = move_gen_tests::legal_moves_after_plies(&mut board, n);
        assert_eq!(result, moves,
                   "Expected {} moves, found {} on board:\n{:?}.", moves, result, board);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;

use config::{Config};

#[derive(PartialEq, Eq, Hash)]
struct Option<'a> {
    names: &'a [&'a str],
    has_args: bool,
    single: bool,
}

struct BuiltinCommand<'a> {
    name: &'a str,
    accept_container: bool,
    options: &'a [&'a Option<'a>],
}

/**
   ----------------------------------              -------------------------------------
  |                                  \            |                                     \
  --> GlobalOptionOrCommand ---> GlobalOptionArg ---> CommandOptionOrContainer ---> CommandOptionArg ---> CommandArg
                  \                               |                   \                               |
                   -------------------------------                     -------------------------------
*/
enum States<'a> {
    GlobalOptionOrCommand,
    // GlobalOptionOrArgOrCommand,
    GlobalOptionArg(&'a Option<'a>),
    CommandOptionOrContainer(&'a BuiltinCommand<'a>),
    // CommandOptionOrArgOrContainer,
    CommandOptionArg(&'a BuiltinCommand<'a>, &'a Option<'a>),
    CommandArg,
}

struct Completion<'a> {
    commands: &'a Vec<&'a String>,
    containers: &'a Vec<&'a String>,
    state: States<'a>,
    single_global_options: HashSet<&'a Option<'a>>,
    single_command_options: HashSet<&'a Option<'a>>,
}

impl<'a> Completion<'a> {
    pub fn new(commands: &'a Vec<&'a String>, containers: &'a Vec<&'a String>) -> Completion<'a> {
        Completion {
            commands: commands,
            containers: containers,
            state: States::GlobalOptionOrCommand,
            single_global_options: HashSet::new(),
            single_command_options: HashSet::new(),
        }
    }

    pub fn trans(&mut self, arg: &str) {
        match self.state {
            States::GlobalOptionOrCommand => {
                for cmd in BUILTIN_COMMANDS {
                    if cmd.name == arg {
                        self.state = States::CommandOptionOrContainer(cmd);
                        return;
                    }
                }
                for &cmd in self.commands {
                    if arg == cmd {
                        self.state = States::CommandArg;
                        return;
                    }
                }
                for opt in GLOBAL_OPTIONS {
                    for &opt_name in opt.names {
                        if arg == opt_name {
                            if opt.has_args {
                                self.state = States::GlobalOptionArg(opt);
                            }
                            if opt.single {
                                self.single_global_options.insert(opt);
                            }
                            return;
                        }
                    }
                }
            },
            States::GlobalOptionArg(_) => {
                self.state = States::GlobalOptionOrCommand;
            },
            States::CommandOptionOrContainer(cmd) => {
                for cmd_opt in cmd.options {
                    for &opt_name in cmd_opt.names {
                        if arg == opt_name {
                            if cmd_opt.has_args {
                                self.state = States::CommandOptionArg(cmd, cmd_opt);
                            }
                            if cmd_opt.single {
                                self.single_command_options.insert(cmd_opt);
                            }
                            return;
                        }
                    }
                }
                for &container_name in self.containers {
                    if arg == container_name {
                        self.state = States::CommandArg;
                        return;
                    }
                }
                self.state = States::CommandArg;
            },
            States::CommandOptionArg(cmd, _) => {
                self.state = States::CommandOptionOrContainer(cmd);
            },
            States::CommandArg => {},
        }
    }

    pub fn complete(&self, cur: &str) -> Vec<&str> {
        let mut completions: Vec<&str> = Vec::new();
        match self.state {
            States::GlobalOptionOrCommand => {
                completions.extend(self.commands.iter().map(|c| &c[..]));
                if cur.starts_with("_") {
                    completions.extend(BUILTIN_COMMANDS.iter().map(|c| c.name));
                }
                for opt in GLOBAL_OPTIONS {
                    if !self.single_global_options.contains(opt) {
                        completions.extend(opt.names);
                    }
                }
            },
            States::CommandOptionOrContainer(cmd) => {
                if cmd.accept_container {
                    completions.extend(self.containers.iter().map(|c| &c[..]));
                }
                for opt in cmd.options {
                    if !self.single_command_options.contains(opt) {
                        completions.extend(opt.names);
                    }
                }
            },
            _ => {},
        }
        completions.retain(|c| c.starts_with(cur));
        return completions;
    }
}

const BUILTIN_COMMANDS: &'static [&'static BuiltinCommand<'static>] = &[
    &BuiltinCommand {
        name: "_build",
        accept_container: true,
        options: &[
            &Option { names: &["--force"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_build_shell",
        accept_container: false,
        options: &[]
    },
    &BuiltinCommand {
        name: "_clean",
        accept_container: false,
        options: &[
            &Option { names: &["--tmp", "--tmp-folders"], has_args: false, single: true },
            &Option { names: &["--old", "--old-containers"], has_args: false, single: true },
            &Option { names: &["--unused"], has_args: false, single: true },
            &Option { names: &["--transient"], has_args: false, single: true },
            &Option { names: &["--global"], has_args: false, single: true },
            &Option { names: &["-n", "--dry-run"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_create_netns",
        accept_container: false,
        options: &[
            &Option { names: &["--dry-run"], has_args: false, single: true },
            &Option { names: &["--no-iptables"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_destroy_netns",
        accept_container: false,
        options: &[
            &Option { names: &["--dry-run"], has_args: false, single: true },
            &Option { names: &["--no-iptables"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_init_storage_dir",
        accept_container: false,
        options: &[]
    },
    &BuiltinCommand {
        name: "_list",
        accept_container: false,
        options: &[]
    },
    &BuiltinCommand {
        name: "_pack_image",
        accept_container: true,
        options: &[
            &Option { names: &["-f", "--file"], has_args: true, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_run",
        accept_container: true,
        options: &[
            &Option { names: &["-W", "--writable"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_run_in_netns",
        accept_container: true,
        options: &[
            &Option { names: &["--pid"], has_args: true, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_version_hash",
        accept_container: true,
        options: &[
            &Option { names: &["-s", "--short"], has_args: false, single: true },
            &Option { names: &["-fd3"], has_args: false, single: true },
        ]
    },
];

const GLOBAL_OPTIONS: &'static [&'static Option<'static>] = &[
    &Option { names: &["-E", "--env", "--environ"], has_args: true, single: false },
    &Option { names: &["-e", "--use-env"], has_args: true, single: false },
    &Option { names: &["--ignore-owner-check"], has_args: false, single: true },
    &Option { names: &["--no-build"], has_args: false, single: true },
    &Option { names: &["--no-version-check"], has_args: false, single: true },
];

pub fn generate_completions(config: &Config, args: Vec<String>) -> Result<i32, String> {
    let default_cur_arg = "".to_string();
    let mut splitted_args = args.splitn(2, |a| a == "--");
    let full_args = match splitted_args.next() {
        Some(a) => a.iter().collect::<Vec<_>>(),
        None => vec!(),
    };
    let cur_arg = match splitted_args.next() {
        Some(a) => a.get(0).unwrap_or(&default_cur_arg),
        None => &default_cur_arg,
    };

    let commands = config.commands.keys().collect::<Vec<_>>();
    let containers = config.containers.keys().collect::<Vec<_>>();
    let mut state = Completion::new(&commands, &containers);
    for arg in full_args {
        state.trans(arg);
    }
    for comp in state.complete(cur_arg) {
        println!("{}", comp);
    }

    Ok(0)
}
<commit_msg>Transition table for completion states<commit_after>use std::collections::HashSet;

use config::{Config};

#[derive(PartialEq, Eq, Hash)]
struct Option<'a> {
    names: &'a [&'a str],
    has_args: bool,
    single: bool,
}

struct BuiltinCommand<'a> {
    name: &'a str,
    accept_container: bool,
    options: &'a [&'a Option<'a>],
}

/**

Transition table:
             _______________________
 +——————————|                       |
 |  +———————| GlobalOptionOrCommand |<———+
 |  |  +————|_______________________|    |
 |  |  |                                 |
 |  |  |        _________________        |
 |  |  |       |                 |       |
 |  |  +——————>| GlobalOptionArg |———————+
 |  |          |_________________|
 |  |
 |  |       __________________________
 |  +—————>|                          |
 |  +——————| CommandOptionOrContainer |<——+
 |  |  +———|__________________________|   |
 |  |  |                                  |
 |  |  |        __________________        |
 |  |  |       |                  |       |
 |  |  +——————>| CommandOptionArg |———————+
 |  |          |__________________|
 |  |
 |  |             ____________
 |  +———————————>|            |
 |               | CommandArg |
 +——————————————>|____________|

*/
enum States<'a> {
    GlobalOptionOrCommand,
    GlobalOptionArg(&'a Option<'a>),
    CommandOptionOrContainer(&'a BuiltinCommand<'a>),
    CommandOptionArg(&'a BuiltinCommand<'a>, &'a Option<'a>),
    CommandArg,
}

struct Completion<'a> {
    commands: &'a Vec<&'a String>,
    containers: &'a Vec<&'a String>,
    state: States<'a>,
    single_global_options: HashSet<&'a Option<'a>>,
    single_command_options: HashSet<&'a Option<'a>>,
}

impl<'a> Completion<'a> {
    pub fn new(commands: &'a Vec<&'a String>, containers: &'a Vec<&'a String>) -> Completion<'a> {
        Completion {
            commands: commands,
            containers: containers,
            state: States::GlobalOptionOrCommand,
            single_global_options: HashSet::new(),
            single_command_options: HashSet::new(),
        }
    }

    pub fn trans(&mut self, arg: &str) {
        match self.state {
            States::GlobalOptionOrCommand => {
                for cmd in BUILTIN_COMMANDS {
                    if cmd.name == arg {
                        self.state = States::CommandOptionOrContainer(cmd);
                        return;
                    }
                }
                for &cmd in self.commands {
                    if arg == cmd {
                        self.state = States::CommandArg;
                        return;
                    }
                }
                for opt in GLOBAL_OPTIONS {
                    for &opt_name in opt.names {
                        if arg == opt_name {
                            if opt.has_args {
                                self.state = States::GlobalOptionArg(opt);
                            }
                            if opt.single {
                                self.single_global_options.insert(opt);
                            }
                            return;
                        }
                    }
                }
            },
            States::GlobalOptionArg(_) => {
                self.state = States::GlobalOptionOrCommand;
            },
            States::CommandOptionOrContainer(cmd) => {
                for cmd_opt in cmd.options {
                    for &opt_name in cmd_opt.names {
                        if arg == opt_name {
                            if cmd_opt.has_args {
                                self.state = States::CommandOptionArg(cmd, cmd_opt);
                            }
                            if cmd_opt.single {
                                self.single_command_options.insert(cmd_opt);
                            }
                            return;
                        }
                    }
                }
                for &container_name in self.containers {
                    if arg == container_name {
                        self.state = States::CommandArg;
                        return;
                    }
                }
                self.state = States::CommandArg;
            },
            States::CommandOptionArg(cmd, _) => {
                self.state = States::CommandOptionOrContainer(cmd);
            },
            States::CommandArg => {},
        }
    }

    pub fn complete(&self, cur: &str) -> Vec<&str> {
        let mut completions: Vec<&str> = Vec::new();
        match self.state {
            States::GlobalOptionOrCommand => {
                completions.extend(self.commands.iter().map(|c| &c[..]));
                if cur.starts_with("_") {
                    completions.extend(BUILTIN_COMMANDS.iter().map(|c| c.name));
                }
                for opt in GLOBAL_OPTIONS {
                    if !self.single_global_options.contains(opt) {
                        completions.extend(opt.names);
                    }
                }
            },
            States::CommandOptionOrContainer(cmd) => {
                if cmd.accept_container {
                    completions.extend(self.containers.iter().map(|c| &c[..]));
                }
                for opt in cmd.options {
                    if !self.single_command_options.contains(opt) {
                        completions.extend(opt.names);
                    }
                }
            },
            _ => {},
        }
        completions.retain(|c| c.starts_with(cur));
        return completions;
    }
}

const BUILTIN_COMMANDS: &'static [&'static BuiltinCommand<'static>] = &[
    &BuiltinCommand {
        name: "_build",
        accept_container: true,
        options: &[
            &Option { names: &["--force"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_build_shell",
        accept_container: false,
        options: &[]
    },
    &BuiltinCommand {
        name: "_clean",
        accept_container: false,
        options: &[
            &Option { names: &["--tmp", "--tmp-folders"], has_args: false, single: true },
            &Option { names: &["--old", "--old-containers"], has_args: false, single: true },
            &Option { names: &["--unused"], has_args: false, single: true },
            &Option { names: &["--transient"], has_args: false, single: true },
            &Option { names: &["--global"], has_args: false, single: true },
            &Option { names: &["-n", "--dry-run"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_create_netns",
        accept_container: false,
        options: &[
            &Option { names: &["--dry-run"], has_args: false, single: true },
            &Option { names: &["--no-iptables"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_destroy_netns",
        accept_container: false,
        options: &[
            &Option { names: &["--dry-run"], has_args: false, single: true },
            &Option { names: &["--no-iptables"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_init_storage_dir",
        accept_container: false,
        options: &[]
    },
    &BuiltinCommand {
        name: "_list",
        accept_container: false,
        options: &[]
    },
    &BuiltinCommand {
        name: "_pack_image",
        accept_container: true,
        options: &[
            &Option { names: &["-f", "--file"], has_args: true, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_run",
        accept_container: true,
        options: &[
            &Option { names: &["-W", "--writable"], has_args: false, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_run_in_netns",
        accept_container: true,
        options: &[
            &Option { names: &["--pid"], has_args: true, single: true },
        ]
    },
    &BuiltinCommand {
        name: "_version_hash",
        accept_container: true,
        options: &[
            &Option { names: &["-s", "--short"], has_args: false, single: true },
            &Option { names: &["-fd3"], has_args: false, single: true },
        ]
    },
];

const GLOBAL_OPTIONS: &'static [&'static Option<'static>] = &[
    &Option { names: &["-E", "--env", "--environ"], has_args: true, single: false },
    &Option { names: &["-e", "--use-env"], has_args: true, single: false },
    &Option { names: &["--ignore-owner-check"], has_args: false, single: true },
    &Option { names: &["--no-build"], has_args: false, single: true },
    &Option { names: &["--no-version-check"], has_args: false, single: true },
];

pub fn generate_completions(config: &Config, args: Vec<String>) -> Result<i32, String> {
    let default_cur_arg = "".to_string();
    let mut splitted_args = args.splitn(2, |a| a == "--");
    let full_args = match splitted_args.next() {
        Some(a) => a.iter().collect::<Vec<_>>(),
        None => vec!(),
    };
    let cur_arg = match splitted_args.next() {
        Some(a) => a.get(0).unwrap_or(&default_cur_arg),
        None => &default_cur_arg,
    };

    let commands = config.commands.keys().collect::<Vec<_>>();
    let containers = config.containers.keys().collect::<Vec<_>>();
    let mut state = Completion::new(&commands, &containers);
    for arg in full_args {
        state.trans(arg);
    }
    for comp in state.complete(cur_arg) {
        println!("{}", comp);
    }

    Ok(0)
}
<|endoftext|>