<commit_before>#![feature(test)] // compiletest_rs requires this attribute
#![feature(once_cell)]

use compiletest_rs as compiletest;
use compiletest_rs::common::Mode as TestMode;

use std::env::{self, remove_var, set_var, var_os};
use std::ffi::{OsStr, OsString};
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

mod cargo;

// whether to run internal tests or not
const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal-lints");

fn host_lib() -> PathBuf {
    option_env!("HOST_LIBS").map_or(cargo::CARGO_TARGET_DIR.join(env!("PROFILE")), PathBuf::from)
}

fn clippy_driver_path() -> PathBuf {
    option_env!("CLIPPY_DRIVER_PATH").map_or(cargo::TARGET_LIB.join("clippy-driver"), PathBuf::from)
}

// When we'll want to use `extern crate ..` for a dependency that is used
// both by the crate and the compiler itself, we can't simply pass -L flags
// as we'll get a duplicate matching versions. Instead, disambiguate with
// `--extern dep=path`.
// See https://github.com/rust-lang/rust-clippy/issues/4015.
//
// FIXME: We cannot use `cargo build --message-format=json` to resolve to dependency files.
//        Because it would force-rebuild if the options passed to `build` command is not the same
//        as what we manually pass to `cargo` invocation
fn third_party_crates() -> String {
    use std::collections::HashMap;
    static CRATES: &[&str] = &["serde", "serde_derive", "regex", "clippy_lints", "syn", "quote"];
    let dep_dir = cargo::TARGET_LIB.join("deps");
    let mut crates: HashMap<&str, PathBuf> = HashMap::with_capacity(CRATES.len());
    for entry in fs::read_dir(dep_dir).unwrap() {
        let path = match entry {
            Ok(entry) => entry.path(),
            Err(_) => continue,
        };
        if let Some(name) = path.file_name().and_then(OsStr::to_str) {
            for dep in CRATES {
                if name.starts_with(&format!("lib{}-", dep))
                    && name.rsplit('.').next().map(|ext| ext.eq_ignore_ascii_case("rlib")) == Some(true)
                {
                    if let Some(old) = crates.insert(dep, path.clone()) {
                        panic!(
                            "\n---------------------------------------------------\n\n \
                            Found multiple rlibs for crate `{}`: `{:?}` and `{:?}`.\n \
                            Probably, you need to run `cargo clean` before running tests again.\n \
                            \nFor details on that error see https://github.com/rust-lang/rust-clippy/issues/7343 \
                            \n---------------------------------------------------\n",
                            dep, old, path
                        );
                    }
                    break;
                }
            }
        }
    }

    let v: Vec<_> = crates
        .into_iter()
        .map(|(dep, path)| format!("--extern {}={}", dep, path.display()))
        .collect();
    v.join(" ")
}

fn default_config() -> compiletest::Config {
    let mut config = compiletest::Config::default();

    if let Ok(filters) = env::var("TESTNAME") {
        config.filters = filters.split(',').map(std::string::ToString::to_string).collect();
    }

    if let Some(path) = option_env!("RUSTC_LIB_PATH") {
        let path = PathBuf::from(path);
        config.run_lib_path = path.clone();
        config.compile_lib_path = path;
    }

    config.target_rustcflags = Some(format!(
        "--emit=metadata -L {0} -L {1} -Dwarnings -Zui-testing {2}",
        host_lib().join("deps").display(),
        cargo::TARGET_LIB.join("deps").display(),
        third_party_crates(),
    ));

    config.build_base = host_lib().join("test_build_base");
    config.rustc_path = clippy_driver_path();
    config
}

fn run_ui(cfg: &mut compiletest::Config) {
    cfg.mode = TestMode::Ui;
    cfg.src_base = Path::new("tests").join("ui");
    // use tests/clippy.toml
    let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
    compiletest::run_tests(cfg);
}

fn run_internal_tests(cfg: &mut compiletest::Config) {
    // only run internal tests with the internal-tests feature
    if !RUN_INTERNAL_TESTS {
        return;
    }
    cfg.mode = TestMode::Ui;
    cfg.src_base = Path::new("tests").join("ui-internal");
    compiletest::run_tests(cfg);
}

fn run_ui_toml(config: &mut compiletest::Config) {
    fn run_tests(config: &compiletest::Config, mut tests: Vec<tester::TestDescAndFn>) -> Result<bool, io::Error> {
        let mut result = true;
        let opts = compiletest::test_opts(config);
        for dir in fs::read_dir(&config.src_base)? {
            let dir = dir?;
            if !dir.file_type()?.is_dir() {
                continue;
            }
            let dir_path = dir.path();
            let _g = VarGuard::set("CARGO_MANIFEST_DIR", &dir_path);
            for file in fs::read_dir(&dir_path)? {
                let file = file?;
                let file_path = file.path();
                if file.file_type()?.is_dir() {
                    continue;
                }
                if file_path.extension() != Some(OsStr::new("rs")) {
                    continue;
                }
                let paths = compiletest::common::TestPaths {
                    file: file_path,
                    base: config.src_base.clone(),
                    relative_dir: dir_path.file_name().unwrap().into(),
                };
                let test_name = compiletest::make_test_name(config, &paths);
                let index = tests
                    .iter()
                    .position(|test| test.desc.name == test_name)
                    .expect("The test should be in there");
                result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
            }
        }
        Ok(result)
    }

    config.mode = TestMode::Ui;
    config.src_base = Path::new("tests").join("ui-toml").canonicalize().unwrap();

    let tests = compiletest::make_tests(config);

    let res = run_tests(config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            panic!("I/O failure during tests: {:?}", e);
        },
    }
}

fn run_ui_cargo(config: &mut compiletest::Config) {
    fn run_tests(
        config: &compiletest::Config,
        filters: &[String],
        mut tests: Vec<tester::TestDescAndFn>,
    ) -> Result<bool, io::Error> {
        let mut result = true;
        let opts = compiletest::test_opts(config);

        for dir in fs::read_dir(&config.src_base)? {
            let dir = dir?;
            if !dir.file_type()?.is_dir() {
                continue;
            }

            // Use the filter if provided
            let dir_path = dir.path();
            for filter in filters {
                if !dir_path.ends_with(filter) {
                    continue;
                }
            }

            for case in fs::read_dir(&dir_path)? {
                let case = case?;
                if !case.file_type()?.is_dir() {
                    continue;
                }

                let src_path = case.path().join("src");

                // When switching between branches, if the previous branch had a test
                // that the current branch does not have, the directory is not removed
                // because an ignored Cargo.lock file exists.
                if !src_path.exists() {
                    continue;
                }

                env::set_current_dir(&src_path)?;
                for file in fs::read_dir(&src_path)? {
                    let file = file?;
                    if file.file_type()?.is_dir() {
                        continue;
                    }

                    // Search for the main file to avoid running a test for each file in the project
                    let file_path = file.path();
                    match file_path.file_name().and_then(OsStr::to_str) {
                        Some("main.rs") => {},
                        _ => continue,
                    }
                    let _g = VarGuard::set("CLIPPY_CONF_DIR", case.path());
                    let paths = compiletest::common::TestPaths {
                        file: file_path,
                        base: config.src_base.clone(),
                        relative_dir: src_path.strip_prefix(&config.src_base).unwrap().into(),
                    };
                    let test_name = compiletest::make_test_name(config, &paths);
                    let index = tests
                        .iter()
                        .position(|test| test.desc.name == test_name)
                        .expect("The test should be in there");
                    result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
                }
            }
        }
        Ok(result)
    }

    if cargo::is_rustc_test_suite() {
        return;
    }

    config.mode = TestMode::Ui;
    config.src_base = Path::new("tests").join("ui-cargo").canonicalize().unwrap();

    let tests = compiletest::make_tests(config);

    let current_dir = env::current_dir().unwrap();
    let res = run_tests(config, &config.filters, tests);
    env::set_current_dir(current_dir).unwrap();

    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            panic!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("__CLIPPY_INTERNAL_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    let mut config = default_config();
    run_ui(&mut config);
    run_ui_toml(&mut config);
    run_ui_cargo(&mut config);
    run_internal_tests(&mut config);
}

/// Restores an env var on drop
#[must_use]
struct VarGuard {
    key: &'static str,
    value: Option<OsString>,
}

impl VarGuard {
    fn set(key: &'static str, val: impl AsRef<OsStr>) -> Self {
        let value = var_os(key);
        set_var(key, val);
        Self { key, value }
    }
}

impl Drop for VarGuard {
    fn drop(&mut self) {
        match self.value.as_deref() {
            None => remove_var(self.key),
            Some(value) => set_var(self.key, value),
        }
    }
}
<commit_msg>Provide different message for bootstrapped compiler<commit_after>#![feature(test)] // compiletest_rs requires this attribute
#![feature(once_cell)]

use compiletest_rs as compiletest;
use compiletest_rs::common::Mode as TestMode;

use std::env::{self, remove_var, set_var, var_os};
use std::ffi::{OsStr, OsString};
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

mod cargo;

// whether to run internal tests or not
const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal-lints");

fn host_lib() -> PathBuf {
    option_env!("HOST_LIBS").map_or(cargo::CARGO_TARGET_DIR.join(env!("PROFILE")), PathBuf::from)
}

fn clippy_driver_path() -> PathBuf {
    option_env!("CLIPPY_DRIVER_PATH").map_or(cargo::TARGET_LIB.join("clippy-driver"), PathBuf::from)
}

// When we'll want to use `extern crate ..` for a dependency that is used
// both by the crate and the compiler itself, we can't simply pass -L flags
// as we'll get a duplicate matching versions. Instead, disambiguate with
// `--extern dep=path`.
// See https://github.com/rust-lang/rust-clippy/issues/4015.
//
// FIXME: We cannot use `cargo build --message-format=json` to resolve to dependency files.
//        Because it would force-rebuild if the options passed to `build` command is not the same
//        as what we manually pass to `cargo` invocation
fn third_party_crates() -> String {
    use std::collections::HashMap;
    static CRATES: &[&str] = &["serde", "serde_derive", "regex", "clippy_lints", "syn", "quote"];
    let dep_dir = cargo::TARGET_LIB.join("deps");
    let mut crates: HashMap<&str, PathBuf> = HashMap::with_capacity(CRATES.len());
    for entry in fs::read_dir(dep_dir).unwrap() {
        let path = match entry {
            Ok(entry) => entry.path(),
            Err(_) => continue,
        };
        if let Some(name) = path.file_name().and_then(OsStr::to_str) {
            for dep in CRATES {
                if name.starts_with(&format!("lib{}-", dep))
                    && name.rsplit('.').next().map(|ext| ext.eq_ignore_ascii_case("rlib")) == Some(true)
                {
                    if let Some(old) = crates.insert(dep, path.clone()) {
                        // Check which action should be done in order to remove compiled deps.
                        // If pre-installed version of compiler is used, `cargo clean` will do.
                        // Otherwise (for bootstrapped compiler), the dependencies directory
                        // must be removed manually.
                        let suggested_action = if std::env::var_os("RUSTC_BOOTSTRAP").is_some() {
                            "remove the stageN-tools directory"
                        } else {
                            "run `cargo clean`"
                        };

                        panic!(
                            "\n---------------------------------------------------\n\n \
                            Found multiple rlibs for crate `{}`: `{:?}` and `{:?}`.\n \
                            Probably, you need to {} before running tests again.\n \
                            \nFor details on that error see https://github.com/rust-lang/rust-clippy/issues/7343 \
                            \n---------------------------------------------------\n",
                            dep, old, path, suggested_action
                        );
                    }
                    break;
                }
            }
        }
    }

    let v: Vec<_> = crates
        .into_iter()
        .map(|(dep, path)| format!("--extern {}={}", dep, path.display()))
        .collect();
    v.join(" ")
}

fn default_config() -> compiletest::Config {
    let mut config = compiletest::Config::default();

    if let Ok(filters) = env::var("TESTNAME") {
        config.filters = filters.split(',').map(std::string::ToString::to_string).collect();
    }

    if let Some(path) = option_env!("RUSTC_LIB_PATH") {
        let path = PathBuf::from(path);
        config.run_lib_path = path.clone();
        config.compile_lib_path = path;
    }

    config.target_rustcflags = Some(format!(
        "--emit=metadata -L {0} -L {1} -Dwarnings -Zui-testing {2}",
        host_lib().join("deps").display(),
        cargo::TARGET_LIB.join("deps").display(),
        third_party_crates(),
    ));

    config.build_base = host_lib().join("test_build_base");
    config.rustc_path = clippy_driver_path();
    config
}

fn run_ui(cfg: &mut compiletest::Config) {
    cfg.mode = TestMode::Ui;
    cfg.src_base = Path::new("tests").join("ui");
    // use tests/clippy.toml
    let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
    compiletest::run_tests(cfg);
}

fn run_internal_tests(cfg: &mut compiletest::Config) {
    // only run internal tests with the internal-tests feature
    if !RUN_INTERNAL_TESTS {
        return;
    }
    cfg.mode = TestMode::Ui;
    cfg.src_base = Path::new("tests").join("ui-internal");
    compiletest::run_tests(cfg);
}

fn run_ui_toml(config: &mut compiletest::Config) {
    fn run_tests(config: &compiletest::Config, mut tests: Vec<tester::TestDescAndFn>) -> Result<bool, io::Error> {
        let mut result = true;
        let opts = compiletest::test_opts(config);
        for dir in fs::read_dir(&config.src_base)? {
            let dir = dir?;
            if !dir.file_type()?.is_dir() {
                continue;
            }
            let dir_path = dir.path();
            let _g = VarGuard::set("CARGO_MANIFEST_DIR", &dir_path);
            for file in fs::read_dir(&dir_path)? {
                let file = file?;
                let file_path = file.path();
                if file.file_type()?.is_dir() {
                    continue;
                }
                if file_path.extension() != Some(OsStr::new("rs")) {
                    continue;
                }
                let paths = compiletest::common::TestPaths {
                    file: file_path,
                    base: config.src_base.clone(),
                    relative_dir: dir_path.file_name().unwrap().into(),
                };
                let test_name = compiletest::make_test_name(config, &paths);
                let index = tests
                    .iter()
                    .position(|test| test.desc.name == test_name)
                    .expect("The test should be in there");
                result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
            }
        }
        Ok(result)
    }

    config.mode = TestMode::Ui;
    config.src_base = Path::new("tests").join("ui-toml").canonicalize().unwrap();

    let tests = compiletest::make_tests(config);

    let res = run_tests(config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            panic!("I/O failure during tests: {:?}", e);
        },
    }
}

fn run_ui_cargo(config: &mut compiletest::Config) {
    fn run_tests(
        config: &compiletest::Config,
        filters: &[String],
        mut tests: Vec<tester::TestDescAndFn>,
    ) -> Result<bool, io::Error> {
        let mut result = true;
        let opts = compiletest::test_opts(config);

        for dir in fs::read_dir(&config.src_base)? {
            let dir = dir?;
            if !dir.file_type()?.is_dir() {
                continue;
            }

            // Use the filter if provided
            let dir_path = dir.path();
            for filter in filters {
                if !dir_path.ends_with(filter) {
                    continue;
                }
            }

            for case in fs::read_dir(&dir_path)? {
                let case = case?;
                if !case.file_type()?.is_dir() {
                    continue;
                }

                let src_path = case.path().join("src");

                // When switching between branches, if the previous branch had a test
                // that the current branch does not have, the directory is not removed
                // because an ignored Cargo.lock file exists.
                if !src_path.exists() {
                    continue;
                }

                env::set_current_dir(&src_path)?;
                for file in fs::read_dir(&src_path)? {
                    let file = file?;
                    if file.file_type()?.is_dir() {
                        continue;
                    }

                    // Search for the main file to avoid running a test for each file in the project
                    let file_path = file.path();
                    match file_path.file_name().and_then(OsStr::to_str) {
                        Some("main.rs") => {},
                        _ => continue,
                    }
                    let _g = VarGuard::set("CLIPPY_CONF_DIR", case.path());
                    let paths = compiletest::common::TestPaths {
                        file: file_path,
                        base: config.src_base.clone(),
                        relative_dir: src_path.strip_prefix(&config.src_base).unwrap().into(),
                    };
                    let test_name = compiletest::make_test_name(config, &paths);
                    let index = tests
                        .iter()
                        .position(|test| test.desc.name == test_name)
                        .expect("The test should be in there");
                    result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
                }
            }
        }
        Ok(result)
    }

    if cargo::is_rustc_test_suite() {
        return;
    }

    config.mode = TestMode::Ui;
    config.src_base = Path::new("tests").join("ui-cargo").canonicalize().unwrap();

    let tests = compiletest::make_tests(config);

    let current_dir = env::current_dir().unwrap();
    let res = run_tests(config, &config.filters, tests);
    env::set_current_dir(current_dir).unwrap();

    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            panic!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("__CLIPPY_INTERNAL_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    let mut config = default_config();
    run_ui(&mut config);
    run_ui_toml(&mut config);
    run_ui_cargo(&mut config);
    run_internal_tests(&mut config);
}

/// Restores an env var on drop
#[must_use]
struct VarGuard {
    key: &'static str,
    value: Option<OsString>,
}

impl VarGuard {
    fn set(key: &'static str, val: impl AsRef<OsStr>) -> Self {
        let value = var_os(key);
        set_var(key, val);
        Self { key, value }
    }
}

impl Drop for VarGuard {
    fn drop(&mut self) {
        match self.value.as_deref() {
            None => remove_var(self.key),
            Some(value) => set_var(self.key, value),
        }
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

use compiletest_rs as compiletest;
extern crate test;

use std::env::{set_var, var};
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

#[must_use]
fn clippy_driver_path() -> PathBuf {
    if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
        PathBuf::from(path)
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/clippy-driver"))
    }
}

#[must_use]
fn host_libs() -> PathBuf {
    if let Some(path) = option_env!("HOST_LIBS") {
        PathBuf::from(path)
    } else {
        Path::new("target").join(env!("PROFILE"))
    }
}

#[must_use]
fn target_libs() -> Option<PathBuf> {
    option_env!("TARGET_LIBS").map(PathBuf::from)
}

#[must_use]
fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

#[must_use]
fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn config(mode: &str, dir: PathBuf) -> compiletest::Config {
    let mut config = compiletest::Config::default();

    let cfg_mode = mode.parse().expect("Invalid mode");
    if let Ok(name) = var::<&str>("TESTNAME") {
        config.filter = Some(name)
    }

    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }

    // When we'll want to use `extern crate ..` for a dependency that is used
    // both by the crate and the compiler itself, we can't simply pass -L flags
    // as we'll get a duplicate matching versions. Instead, disambiguate with
    // `--extern dep=path`.
    // See https://github.com/rust-lang/rust-clippy/issues/4015.
    let needs_disambiguation = ["serde", "regex", "clippy_lints"];
    // This assumes that deps are compiled (they are for Cargo integration tests).
    let deps = fs::read_dir(host_libs().join("deps")).unwrap();
    let deps: Vec<_> = if let Some(target_libs) = target_libs() {
        deps.chain(fs::read_dir(target_libs.join("deps")).unwrap()).collect()
    } else {
        deps.collect()
    };
    let disambiguated = deps
        .into_iter()
        .filter_map(|dep| {
            let path = dep.ok()?.path();
            let name = path.file_name()?.to_string_lossy();
            // NOTE: This only handles a single dep
            // https://github.com/laumann/compiletest-rs/issues/101
            needs_disambiguation.iter().find_map(|dep| {
                if name.starts_with(&format!("lib{}-", dep)) && name.ends_with(".rlib") {
                    Some(format!("--extern {}={}", dep, path.display()))
                } else {
                    None
                }
            })
        })
        .collect::<Vec<_>>();

    config.target_rustcflags = Some(format!(
        "-L {0} -L {0}/deps {1} -Dwarnings -Zui-testing {2}",
        host_libs().display(),
        target_libs().map_or_else(String::new, |path| format!("-L {0} -L {0}/deps", path.display())),
        disambiguated.join(" ")
    ));

    config.mode = cfg_mode;
    config.build_base = if rustc_test_suite().is_some() {
        // we don't need access to the stderr files on travis
        let mut path = PathBuf::from(env!("OUT_DIR"));
        path.push("test_build_base");
        path
    } else {
        let mut path = std::env::current_dir().unwrap();
        path.push("target/debug/test_build_base");
        path
    };
    config.src_base = dir;
    config.rustc_path = clippy_driver_path();
    config
}

fn run_mode(mode: &str, dir: PathBuf) {
    let cfg = config(mode, dir);
    compiletest::run_tests(&cfg);
}

#[allow(clippy::identity_conversion)]
fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<test::TestDescAndFn>) -> Result<bool, io::Error> {
    let mut result = true;
    let opts = compiletest::test_opts(config);
    for dir in fs::read_dir(&config.src_base)? {
        let dir = dir?;
        if !dir.file_type()?.is_dir() {
            continue;
        }
        let dir_path = dir.path();
        set_var("CARGO_MANIFEST_DIR", &dir_path);
        for file in fs::read_dir(&dir_path)? {
            let file = file?;
            let file_path = file.path();
            if !file.file_type()?.is_file() {
                continue;
            }
            if file_path.extension() != Some(OsStr::new("rs")) {
                continue;
            }
            let paths = compiletest::common::TestPaths {
                file: file_path,
                base: config.src_base.clone(),
                relative_dir: dir_path.file_name().unwrap().into(),
            };
            let test_name = compiletest::make_test_name(&config, &paths);
            let index = tests
                .iter()
                .position(|test| test.desc.name == test_name)
                .expect("The test should be in there");
            result &= test::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
        }
    }
    Ok(result)
}

fn run_ui_toml() {
    let path = PathBuf::from("tests/ui-toml").canonicalize().unwrap();
    let config = config("ui", path);
    let tests = compiletest::make_tests(&config);

    let res = run_ui_toml_tests(&config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            println!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("CLIPPY_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    run_mode("ui", "tests/ui".into());
    run_ui_toml();
}
<commit_msg>Only pass rlibs in target deps directory<commit_after>#![feature(test)]

use compiletest_rs as compiletest;
extern crate test;

use std::env::{set_var, var};
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

#[must_use]
fn clippy_driver_path() -> PathBuf {
    if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
        PathBuf::from(path)
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/clippy-driver"))
    }
}

#[must_use]
fn host_libs() -> PathBuf {
    if let Some(path) = option_env!("HOST_LIBS") {
        PathBuf::from(path)
    } else {
        Path::new("target").join(env!("PROFILE"))
    }
}

#[must_use]
fn target_libs() -> Option<PathBuf> {
    option_env!("TARGET_LIBS").map(PathBuf::from)
}

#[must_use]
fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

#[must_use]
fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn config(mode: &str, dir: PathBuf) -> compiletest::Config {
    let mut config = compiletest::Config::default();

    let cfg_mode = mode.parse().expect("Invalid mode");
    if let Ok(name) = var::<&str>("TESTNAME") {
        config.filter = Some(name)
    }

    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }

    // When we'll want to use `extern crate ..` for a dependency that is used
    // both by the crate and the compiler itself, we can't simply pass -L flags
    // as we'll get a duplicate matching versions. Instead, disambiguate with
    // `--extern dep=path`.
    // See https://github.com/rust-lang/rust-clippy/issues/4015.
    let needs_disambiguation = ["serde", "regex", "clippy_lints"];
    // This assumes that deps are compiled (they are for Cargo integration tests).
    let deps = fs::read_dir(target_libs().unwrap_or_else(host_libs).join("deps")).unwrap();
    let disambiguated = deps
        .filter_map(|dep| {
            let path = dep.ok()?.path();
            let name = path.file_name()?.to_string_lossy();
            // NOTE: This only handles a single dep
            // https://github.com/laumann/compiletest-rs/issues/101
            needs_disambiguation.iter().find_map(|dep| {
                if name.starts_with(&format!("lib{}-", dep)) && name.ends_with(".rlib") {
                    Some(format!("--extern {}={}", dep, path.display()))
                } else {
                    None
                }
            })
        })
        .collect::<Vec<_>>();

    config.target_rustcflags = Some(format!(
        "-L {0} -L {0}/deps {1} -Dwarnings -Zui-testing {2}",
        host_libs().display(),
        target_libs().map_or_else(String::new, |path| format!("-L {0} -L {0}/deps", path.display())),
        disambiguated.join(" ")
    ));

    config.mode = cfg_mode;
    config.build_base = if rustc_test_suite().is_some() {
        // we don't need access to the stderr files on travis
        let mut path = PathBuf::from(env!("OUT_DIR"));
        path.push("test_build_base");
        path
    } else {
        let mut path = std::env::current_dir().unwrap();
        path.push("target/debug/test_build_base");
        path
    };
    config.src_base = dir;
    config.rustc_path = clippy_driver_path();
    config
}

fn run_mode(mode: &str, dir: PathBuf) {
    let cfg = config(mode, dir);
    compiletest::run_tests(&cfg);
}

#[allow(clippy::identity_conversion)]
fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<test::TestDescAndFn>) -> Result<bool, io::Error> {
    let mut result = true;
    let opts = compiletest::test_opts(config);
    for dir in fs::read_dir(&config.src_base)? {
        let dir = dir?;
        if !dir.file_type()?.is_dir() {
            continue;
        }
        let dir_path = dir.path();
        set_var("CARGO_MANIFEST_DIR", &dir_path);
        for file in fs::read_dir(&dir_path)? {
            let file = file?;
            let file_path = file.path();
            if !file.file_type()?.is_file() {
                continue;
            }
            if file_path.extension() != Some(OsStr::new("rs")) {
                continue;
            }
            let paths = compiletest::common::TestPaths {
                file: file_path,
                base: config.src_base.clone(),
                relative_dir: dir_path.file_name().unwrap().into(),
            };
            let test_name = compiletest::make_test_name(&config, &paths);
            let index = tests
                .iter()
                .position(|test| test.desc.name == test_name)
                .expect("The test should be in there");
            result &= test::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
        }
    }
    Ok(result)
}

fn run_ui_toml() {
    let path = PathBuf::from("tests/ui-toml").canonicalize().unwrap();
    let config = config("ui", path);
    let tests = compiletest::make_tests(&config);

    let res = run_ui_toml_tests(&config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            println!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("CLIPPY_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    run_mode("ui", "tests/ui".into());
    run_ui_toml();
}
<|endoftext|>


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

fn main() {
    oak_utils::compile_protos(
        &[
            "../../../oak/proto/storage.proto",
            "../../../oak/proto/storage_channel.proto",
        ],
        &["../../.."],
    );
}
<commit_msg>sdk: no need for storage.proto<commit_after>//
// Copyright 2019 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

fn main() {
    oak_utils::compile_protos(&["../../../oak/proto/storage_channel.proto"], &["../../.."]);
}
<|endoftext|>


<commit_before>#[macro_use] extern crate bitflags;
#[macro_use] extern crate wayland_sys;
extern crate libc;

pub use generated::server as protocol;
pub use client::Client;
pub use display::{Display, create_display};
pub use event_loop::{EventLoop, EventLoopHandle, StateGuard};

use wayland_sys::server::wl_resource;
use wayland_sys::common::{wl_interface, wl_argument};

mod client;
mod display;
mod event_loop;

pub trait Resource {
    /// Pointer to the underlying wayland proxy object
    fn ptr(&self) -> *mut wl_resource;
    /// Create an instance from point a wayland pointer
    ///
    /// The pointer must refer to a valid wayland proxy
    /// of the appropriate interface.
    unsafe fn from_ptr(*mut wl_resource) -> Self;
    /// Pointer to the interface representation
    fn interface_ptr() -> *const wl_interface;
    /// Internal wayland name of this interface
    fn interface_name() -> &'static str;
    /// Max version of this interface supported
    fn supported_version() -> u32;
    /// Current version of the interface this resource is instanciated with
    fn version(&self) -> i32;
}

pub unsafe trait Handler<T: Resource> {
    unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, resource: &T, opcode: u32, args: *const wl_argument) -> Result<(),()>;
}

mod generated {
    #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
    #![allow(non_upper_case_globals,non_snake_case,unused_imports)]

    pub mod interfaces {
        include!(concat!(env!("OUT_DIR"), "/wayland_interfaces.rs"));
    }

    pub mod server {
        // Imports that need to be available to submodules
        // but should not be in public API.
        // Will be fixable with pub(restricted).
        #[doc(hidden)] pub use {Resource, EventLoopHandle, Handler, Client};
        #[doc(hidden)] pub use super::interfaces;

        include!(concat!(env!("OUT_DIR"), "/wayland_api.rs"));
    }
}

pub mod sys {
    pub use wayland_sys::server::*;
    pub use wayland_sys::common::*;
}
<commit_msg>server: add missing reexports<commit_after>#[macro_use] extern crate bitflags;
#[macro_use] extern crate wayland_sys;
extern crate libc;

pub use generated::server as protocol;
pub use client::Client;
pub use display::{Display, create_display};
pub use event_loop::{EventLoop, EventLoopHandle, StateGuard, Global, GlobalHandler};

use wayland_sys::server::wl_resource;
use wayland_sys::common::{wl_interface, wl_argument};

mod client;
mod display;
mod event_loop;

pub trait Resource {
    /// Pointer to the underlying wayland proxy object
    fn ptr(&self) -> *mut wl_resource;
    /// Create an instance from point a wayland pointer
    ///
    /// The pointer must refer to a valid wayland proxy
    /// of the appropriate interface.
    unsafe fn from_ptr(*mut wl_resource) -> Self;
    /// Pointer to the interface representation
    fn interface_ptr() -> *const wl_interface;
    /// Internal wayland name of this interface
    fn interface_name() -> &'static str;
    /// Max version of this interface supported
    fn supported_version() -> u32;
    /// Current version of the interface this resource is instanciated with
    fn version(&self) -> i32;
}

pub unsafe trait Handler<T: Resource> {
    unsafe fn message(&mut self, evq: &mut EventLoopHandle, client: &Client, resource: &T, opcode: u32, args: *const wl_argument) -> Result<(),()>;
}

mod generated {
    #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
    #![allow(non_upper_case_globals,non_snake_case,unused_imports)]

    pub mod interfaces {
        include!(concat!(env!("OUT_DIR"), "/wayland_interfaces.rs"));
    }

    pub mod server {
        // Imports that need to be available to submodules
        // but should not be in public API.
        // Will be fixable with pub(restricted).
        #[doc(hidden)] pub use {Resource, EventLoopHandle, Handler, Client};
        #[doc(hidden)] pub use super::interfaces;

        include!(concat!(env!("OUT_DIR"), "/wayland_api.rs"));
    }
}

pub mod sys {
    pub use wayland_sys::server::*;
    pub use wayland_sys::common::*;
}
<|endoftext|>


<commit_before>macro_rules! decode_op(
	($op:ident $handler:ident $data:ident) => (
		match $op {
			0x20 => $handler.add($data),
			0x30 => $handler.addc($data),
			0x28 => $handler.and($data),
			0x38 => $handler.andc($data),
			0x1C => $handler.beq($data),
			0x1D => $handler.bne($data),
			0x24 => $handler.cmpeq($data),
			0x34 => $handler.cmpeqc($data),
			0x26 => $handler.cmple($data),
			0x36 => $handler.cmplec($data),
			0x25 => $handler.cmplt($data),
			0x35 => $handler.cmpltc($data),
			0x23 => $handler.div($data),
			0x33 => $handler.divc($data),
			0x1B => $handler.jmp($data),
			0x18 => $handler.ld($data),
			0x1F => $handler.ldr($data),
			0x22 => $handler.mul($data),
			0x32 => $handler.mulc($data),
			0x29 => $handler.or($data),
			0x39 => $handler.orc($data),
			0x2C => $handler.shl($data),
			0x3C => $handler.shlc($data),
			0x2D => $handler.shr($data),
			0x3D => $handler.shrc($data),
			0x2E => $handler.sra($data),
			0x3E => $handler.srac($data),
			0x21 => $handler.sub($data),
			0x31 => $handler.subc($data),
			0x19 => $handler.st($data),
			0x2A => $handler.xor($data),
			0x3A => $handler.xorc($data),
			0x2B => $handler.xnor($data),
			0x3B => $handler.xnorc($data),
			_ => fail!("Unrecognized opcode.")
		}
)
)

fn each(v: &mut [u32], op: &fn(v: &mut u32)) {
	let mut n = 0;
	while n < v.len() {
		op(&mut v[n]);
		n += 1;
	}
}

struct Mem {
	data:	[u8, ..4096]
}

impl Mem {
	fn read(&self, addr: u32) -> u8 {
		self.data[addr]
	}

	fn read_word(&self, addr: u32) -> u32 {
		let b1 = self.read(addr) as u32;
		let b2 = self.read(addr + 1) as u32;
		let b3 = self.read(addr + 2) as u32;
		let b4 = self.read(addr + 3) as u32;

		(b1 << 24) | (b2 << 16) | (b3 << 8) | b4
	}

	fn write(&mut self, addr: u32, val: u8) {
		self.data[addr] = val;
	}
}

struct Beta {
	pc:			u32,
	register:	[u32, ..31],
	mem:		Mem
}

impl Beta {
	fn reset(&mut self) {
		self.pc = 0;
		do each(self.register) |r| { *r = 0; }

		//println(fmt!("reset. pc at %d", self.pc as int));
	}

	fn tick(&mut self) {
		let instruction: u32 = self.mem.read_word(self.pc);

		// decode invariant part of instruction format
		let op = instruction >> 26;
		let data = instruction & 0x3FFFFFFF;

		println(fmt!("op: %d", op as int));

		decode_op!(op self data)

		self.pc += 4;
		//println(fmt!("tick. pc at %d", self.pc as int));
	}

	fn read_reg(&self, reg: uint) -> u32 {
		match reg {
			0..30	=> self.register[reg],
			31		=> 0,
			_		=> fail!(fmt!("tried to read from nonexistant register %d", reg as int))
		}
	}

	fn write_reg(&mut self, reg: uint, val: u32) {
		match reg {
			0..30	=> self.register[reg] = val,
			31		=> {},
			_		=> fail!(fmt!("tried to write to nonexistant register %d", reg as int))
		};
	}

	fn args(data: u32) -> (u32, u32, u32) {
		(data >> 21, data >> 16, data >> 11)
	}

	fn args_literal(data: u32) -> (u32, u32, u32) {
		(data >> 21, data >> 16, data & 0xFFFF)
	}

	fn exec_op(&mut self, data: u32, exp: &fn(a: u32, b: u32) -> u32) {
		let (r_c, r_a, r_b) = Beta::args(data);
		let a = self.read_reg(r_a as uint);
		let b = self.read_reg(r_b as uint);
		self.write_reg(r_c as uint, exp(a, b));
		println(fmt!("fn \"%?\"", exp));
	}

	fn exec_op_lit(&mut self, data: u32, exp: &fn(a: u32, b: u32) -> u32) {
		let (r_c, r_a, lit) = Beta::args_literal(data);
		let a = self.read_reg(r_a as uint);
		self.write_reg(r_c as uint, exp(a, lit));
		println(fmt!("fn \"%?\"", exp));
	}

	/* INSTRUCTION SET */

	fn add(&mut self, data: u32) {
		self.exec_op(data, |a, b| a + b);
	}

	fn addc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| a + b);
	}

	fn and(&mut self, data: u32) {
		self.exec_op(data, |a, b| a & b);
	}

	fn andc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| a & b);
	}

	fn beq(&mut self, data: u32) {
		let (r_c, r_a, lit) = Beta::args_literal(data);
		let a = self.read_reg(r_a as uint);

		self.write_reg(r_c as uint, self.pc + 4);
		let displacement = ((lit as i32)*4) as u32;
		let target = self.pc + 4 + displacement;

		if(a == 0) { self.pc = target; }
	}

	fn bne(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn cmpeq(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn cmpeqc(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn cmple(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn cmplec(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn cmplt(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn cmpltc(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn div(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn divc(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn jmp(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn ld(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn ldr(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn mul(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn mulc(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn or(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn orc(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn shl(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn shlc(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn shr(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn shrc(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn sra(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn srac(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn sub(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn subc(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn st(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn xor(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn xorc(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn xnor(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn xnorc(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}
}

fn main() {
	let mut b = ~Beta {
		pc: 10u32,
		register: [3u32, ..31],
		mem: Mem {
			data: [0u8, ..4*1024]
		}
	};

	b.reset();
	b.tick();
	println("success");
}
<commit_msg>Implemented bne, cmpeq, cmpeqc, cmple, cmplec, cmplt, cmpltc, div, and divc.<commit_after>macro_rules! decode_op(
	($op:ident $handler:ident $data:ident) => (
		match $op {
			0x20 => $handler.add($data),
			0x30 => $handler.addc($data),
			0x28 => $handler.and($data),
			0x38 => $handler.andc($data),
			0x1C => $handler.beq($data),
			0x1D => $handler.bne($data),
			0x24 => $handler.cmpeq($data),
			0x34 => $handler.cmpeqc($data),
			0x26 => $handler.cmple($data),
			0x36 => $handler.cmplec($data),
			0x25 => $handler.cmplt($data),
			0x35 => $handler.cmpltc($data),
			0x23 => $handler.div($data),
			0x33 => $handler.divc($data),
			0x1B => $handler.jmp($data),
			0x18 => $handler.ld($data),
			0x1F => $handler.ldr($data),
			0x22 => $handler.mul($data),
			0x32 => $handler.mulc($data),
			0x29 => $handler.or($data),
			0x39 => $handler.orc($data),
			0x2C => $handler.shl($data),
			0x3C => $handler.shlc($data),
			0x2D => $handler.shr($data),
			0x3D => $handler.shrc($data),
			0x2E => $handler.sra($data),
			0x3E => $handler.srac($data),
			0x21 => $handler.sub($data),
			0x31 => $handler.subc($data),
			0x19 => $handler.st($data),
			0x2A => $handler.xor($data),
			0x3A => $handler.xorc($data),
			0x2B => $handler.xnor($data),
			0x3B => $handler.xnorc($data),
			_ => fail!("Unrecognized opcode.")
		}
)
)

fn each(v: &mut [u32], op: &fn(v: &mut u32)) {
	let mut n = 0;
	while n < v.len() {
		op(&mut v[n]);
		n += 1;
	}
}

struct Mem {
	data:	[u8, ..4096]
}

impl Mem {
	fn read(&self, addr: u32) -> u8 {
		self.data[addr]
	}

	fn read_word(&self, addr: u32) -> u32 {
		let b1 = self.read(addr) as u32;
		let b2 = self.read(addr + 1) as u32;
		let b3 = self.read(addr + 2) as u32;
		let b4 = self.read(addr + 3) as u32;

		(b1 << 24) | (b2 << 16) | (b3 << 8) | b4
	}

	fn write(&mut self, addr: u32, val: u8) {
		self.data[addr] = val;
	}
}

struct Beta {
	pc:			u32,
	register:	[u32, ..31],
	mem:		Mem
}

impl Beta {
	fn reset(&mut self) {
		self.pc = 0;
		do each(self.register) |r| { *r = 0; }

		//println(fmt!("reset. pc at %d", self.pc as int));
	}

	fn tick(&mut self) {
		let instruction: u32 = self.mem.read_word(self.pc);

		// decode invariant part of instruction format
		let op = instruction >> 26;
		let data = instruction & 0x3FFFFFFF;

		println(fmt!("op: %d", op as int));

		decode_op!(op self data)

		self.pc += 4;
		//println(fmt!("tick. pc at %d", self.pc as int));
	}

	fn read_reg(&self, reg: uint) -> u32 {
		match reg {
			0..30	=> self.register[reg],
			31		=> 0,
			_		=> fail!(fmt!("tried to read from nonexistant register %d", reg as int))
		}
	}

	fn write_reg(&mut self, reg: uint, val: u32) {
		match reg {
			0..30	=> self.register[reg] = val,
			31		=> {},
			_		=> fail!(fmt!("tried to write to nonexistant register %d", reg as int))
		};
	}

	fn args(data: u32) -> (u32, u32, u32) {
		(data >> 21, data >> 16, data >> 11)
	}

	fn args_literal(data: u32) -> (u32, u32, u32) {
		(data >> 21, data >> 16, data & 0xFFFF)
	}

	fn exec_op(&mut self, data: u32, exp: &fn(a: u32, b: u32) -> u32) {
		let (r_c, r_a, r_b) = Beta::args(data);
		let a = self.read_reg(r_a as uint);
		let b = self.read_reg(r_b as uint);
		self.write_reg(r_c as uint, exp(a, b));
		println(fmt!("fn \"%?\"", exp));
	}

	fn exec_op_lit(&mut self, data: u32, exp: &fn(a: u32, b: u32) -> u32) {
		let (r_c, r_a, lit) = Beta::args_literal(data);
		let a = self.read_reg(r_a as uint);
		self.write_reg(r_c as uint, exp(a, lit));
		println(fmt!("fn \"%?\"", exp));
	}

	/* INSTRUCTION SET */

	fn add(&mut self, data: u32) {
		self.exec_op(data, |a, b| a + b);
	}

	fn addc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| a + b);
	}

	fn and(&mut self, data: u32) {
		self.exec_op(data, |a, b| a & b);
	}

	fn andc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| a & b);
	}

	fn beq(&mut self, data: u32) {
		let (r_c, r_a, lit) = Beta::args_literal(data);
		let a = self.read_reg(r_a as uint);

		self.write_reg(r_c as uint, self.pc + 4);
		let displacement = ((lit as i32)*4) as u32;
		let target = self.pc + 4 + displacement;

		if(a == 0) { self.pc = target; }
	}

	fn bne(&mut self, data: u32) {
		let (r_c, r_a, lit) = Beta::args_literal(data);
		let a = self.read_reg(r_a as uint);

		self.write_reg(r_c as uint, self.pc + 4);
		let displacement = ((lit as i32)*4) as u32;
		let target = self.pc + 4 + displacement;

		if(a != 0) { self.pc = target; }
	}

	fn cmpeq(&mut self, data: u32) {
		self.exec_op(data, |a, b| if(a == b) {1} else {0});
	}

	fn cmpeqc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| if(a == b) {1} else {0});
	}

	fn cmple(&mut self, data: u32) {
		self.exec_op(data, |a, b| if(a <= b) {1} else {0});
	}

	fn cmplec(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| if(a <= b) {1} else {0});
	}

	fn cmplt(&mut self, data: u32) {
		self.exec_op(data, |a, b| if(a < b) {1} else {0});
	}

	fn cmpltc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| if(a < b) {1} else {0});
	}

	fn div(&mut self, data: u32) {
		self.exec_op(data, |a, b| a / b);
	}

	fn divc(&mut self, data: u32) {
		self.exec_op_lit(data, |a, b| a / b);
	}

	fn jmp(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn ld(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn ldr(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn mul(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn mulc(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn or(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn orc(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn shl(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn shlc(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn shr(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn shrc(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn sra(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn srac(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn sub(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn subc(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn st(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn xor(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn xorc(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn xnor(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}

	fn xnorc(&mut self, data: u32) {
		println(fmt!("data: %d", data as int));
	}
}

fn main() {
	let mut b = ~Beta {
		pc: 10u32,
		register: [3u32, ..31],
		mem: Mem {
			data: [0u8, ..4*1024]
		}
	};

	b.reset();
	b.tick();
	println("success");
}
<|endoftext|>


<commit_before>//! incremental BLOB I/O
use std::io;
use std::mem;
use std::ptr;

use super::ffi;
use {Error, Result, Connection, DatabaseName};

/// Handle to an open BLOB
pub struct Blob<'conn> {
    conn: &'conn Connection,
    blob: *mut ffi::sqlite3_blob,
    pos: i32,
}

/// Enumeration of possible methods to seek within an BLOB.
pub enum SeekFrom {
    Start(i32),
    End(i32),
    Current(i32),
}

impl Connection {
    /// Open a handle to the BLOB located in `row`, `column`, `table` in database `db`.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `db`/`table`/`column` cannot be converted to a C-compatible string or if the
    /// underlying SQLite BLOB open call fails.
    pub fn blob_open<'a>(&'a self,
                         db: DatabaseName,
                         table: &str,
                         column: &str,
                         row: i64,
                         read_only: bool)
                         -> Result<Blob<'a>> {
        let mut c = self.db.borrow_mut();
        let mut blob = ptr::null_mut();
        let db = try!(db.to_cstring());
        let table = try!(super::str_to_cstring(table));
        let column = try!(super::str_to_cstring(column));
        let rc = unsafe {
            ffi::sqlite3_blob_open(c.db(),
                                   db.as_ptr(),
                                   table.as_ptr(),
                                   column.as_ptr(),
                                   row,
                                   if read_only {
                                       0
                                   } else {
                                       1
                                   },
                                   &mut blob)
        };
        c.decode_result(rc).map(|_| {
            Blob {
                conn: self,
                blob: blob,
                pos: 0,
            }
        })
    }
}

impl<'conn> Blob<'conn> {
    /// Move a BLOB handle to a new row
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite BLOB reopen call fails.
    pub fn reopen(&mut self, row: i64) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_reopen(self.blob, row) };
        if rc != ffi::SQLITE_OK {
            return self.conn.decode_result(rc);
        }
        self.pos = 0;
        Ok(())
    }

    /// Return the size in bytes of the BLOB
    pub fn size(&self) -> i32 {
        unsafe { ffi::sqlite3_blob_bytes(self.blob) }
    }

    /// Write data into a BLOB incrementally
    ///
    /// This function may only modify the contents of the BLOB; it is not possible to increase the size of a BLOB using this API.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `buf` length > i32 max value or if `buf` length + offset > BLOB size
    /// or if the underlying SQLite write call fails.
    pub fn write(&mut self, buf: &[u8]) -> Result<i32> {
        if buf.len() > ::std::i32::MAX as usize {
            return Err(Error {
                code: ffi::SQLITE_TOOBIG,
                message: "buffer too long".to_string(),
            });
        }
        let n = buf.len() as i32;
        let size = self.size();
        if self.pos + n > size {
            return Err(Error {
                code: ffi::SQLITE_MISUSE,
                message: format!("pos = {} + n = {} > size = {}", self.pos, n, size),
            });
        }
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_write(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn.decode_result(rc).map(|_| {
            self.pos += n;
            n
        })
    }

    /// Seek to an offset, in bytes, in BLOB.
    pub fn seek(&mut self, pos: SeekFrom) {
        self.pos = match pos {
            SeekFrom::Start(offset) => offset,
            SeekFrom::Current(offset) => self.pos + offset,
            SeekFrom::End(offset) => self.size() + offset,
        };
    }

    /// Close a BLOB handle
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite close call fails.
    pub fn close(mut self) -> Result<()> {
        self.close_()
    }

    fn close_(&mut self) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_close(self.blob) };
        self.blob = ptr::null_mut();
        self.conn.decode_result(rc)
    }
}

impl<'conn> io::Read for Blob<'conn> {
    /// Read data from a BLOB incrementally
    ///
    /// # Failure
    ///
    /// Will return `Err` if `buf` length > i32 max value or if the underlying SQLite read call fails.
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if buf.len() > ::std::i32::MAX as usize {
            return Err(io::Error::new(io::ErrorKind::InvalidInput, Error {
                code: ffi::SQLITE_TOOBIG,
                message: "buffer too long".to_string(),
            }));
        }
        let mut n = buf.len() as i32;
        let size = self.size();
        if self.pos + n > size {
            n = size - self.pos;
        }
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_read(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn.decode_result(rc).map(|_| {
            self.pos += n;
            n as usize
        }).map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }
}

#[allow(unused_must_use)]
impl<'conn> Drop for Blob<'conn> {
    fn drop(&mut self) {
        self.close_();
    }
}

#[cfg(test)]
mod test {
    use std::io::Read;
    use {Connection, DatabaseName};

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_blob() {
        let db = Connection::open_in_memory().unwrap();
        let sql = "BEGIN;
                CREATE TABLE test (content BLOB);
                INSERT INTO test VALUES (ZEROBLOB(10));
                END;";
        db.execute_batch(sql).unwrap();
        let rowid = db.last_insert_rowid();

        let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
        blob.write(b"Clob").unwrap();
        let err = blob.write(b"5678901");
        // writeln!(io::stderr(), "{:?}", err);
        assert!(err.is_err());

        assert!(blob.reopen(rowid).is_ok());
        assert!(blob.close().is_ok());

        blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, true).unwrap();
        let mut bytes = [0u8; 5];
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(0, blob.read(&mut bytes[..]).unwrap());

        assert!(blob.reopen(rowid).is_ok());
        blob.seek(super::SeekFrom::Start(0));
    }
}
<commit_msg>Move Blob's `write` to an impl of std::io::Write.<commit_after>//! incremental BLOB I/O
use std::io;
use std::mem;
use std::ptr;

use super::ffi;
use {Error, Result, Connection, DatabaseName};

/// Handle to an open BLOB
pub struct Blob<'conn> {
    conn: &'conn Connection,
    blob: *mut ffi::sqlite3_blob,
    pos: i32,
}

/// Enumeration of possible methods to seek within an BLOB.
pub enum SeekFrom {
    Start(i32),
    End(i32),
    Current(i32),
}

impl Connection {
    /// Open a handle to the BLOB located in `row`, `column`, `table` in database `db`.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `db`/`table`/`column` cannot be converted to a C-compatible string or if the
    /// underlying SQLite BLOB open call fails.
    pub fn blob_open<'a>(&'a self,
                         db: DatabaseName,
                         table: &str,
                         column: &str,
                         row: i64,
                         read_only: bool)
                         -> Result<Blob<'a>> {
        let mut c = self.db.borrow_mut();
        let mut blob = ptr::null_mut();
        let db = try!(db.to_cstring());
        let table = try!(super::str_to_cstring(table));
        let column = try!(super::str_to_cstring(column));
        let rc = unsafe {
            ffi::sqlite3_blob_open(c.db(),
                                   db.as_ptr(),
                                   table.as_ptr(),
                                   column.as_ptr(),
                                   row,
                                   if read_only {
                                       0
                                   } else {
                                       1
                                   },
                                   &mut blob)
        };
        c.decode_result(rc).map(|_| {
            Blob {
                conn: self,
                blob: blob,
                pos: 0,
            }
        })
    }
}

impl<'conn> Blob<'conn> {
    /// Move a BLOB handle to a new row
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite BLOB reopen call fails.
    pub fn reopen(&mut self, row: i64) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_reopen(self.blob, row) };
        if rc != ffi::SQLITE_OK {
            return self.conn.decode_result(rc);
        }
        self.pos = 0;
        Ok(())
    }

    /// Return the size in bytes of the BLOB
    pub fn size(&self) -> i32 {
        unsafe { ffi::sqlite3_blob_bytes(self.blob) }
    }

    /// Seek to an offset, in bytes, in BLOB.
    pub fn seek(&mut self, pos: SeekFrom) {
        self.pos = match pos {
            SeekFrom::Start(offset) => offset,
            SeekFrom::Current(offset) => self.pos + offset,
            SeekFrom::End(offset) => self.size() + offset,
        };
    }

    /// Close a BLOB handle
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite close call fails.
    pub fn close(mut self) -> Result<()> {
        self.close_()
    }

    fn close_(&mut self) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_close(self.blob) };
        self.blob = ptr::null_mut();
        self.conn.decode_result(rc)
    }
}

impl<'conn> io::Read for Blob<'conn> {
    /// Read data from a BLOB incrementally
    ///
    /// # Failure
    ///
    /// Will return `Err` if `buf` length > i32 max value or if the underlying SQLite read call fails.
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if buf.len() > ::std::i32::MAX as usize {
            return Err(io::Error::new(io::ErrorKind::InvalidInput, Error {
                code: ffi::SQLITE_TOOBIG,
                message: "buffer too long".to_string(),
            }));
        }
        let mut n = buf.len() as i32;
        let size = self.size();
        if self.pos + n > size {
            n = size - self.pos;
        }
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_read(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn.decode_result(rc).map(|_| {
            self.pos += n;
            n as usize
        }).map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }
}

impl<'conn> io::Write for Blob<'conn> {
    /// Write data into a BLOB incrementally
    ///
    /// This function may only modify the contents of the BLOB; it is not possible to increase the size of a BLOB using this API.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `buf` length > i32 max value or if `buf` length + offset > BLOB size
    /// or if the underlying SQLite write call fails.
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if buf.len() > ::std::i32::MAX as usize {
            return Err(io::Error::new(io::ErrorKind::InvalidInput, Error {
                code: ffi::SQLITE_TOOBIG,
                message: "buffer too long".to_string(),
            }));
        }
        let n = buf.len() as i32;
        let size = self.size();
        if self.pos + n > size {
            return Err(io::Error::new(io::ErrorKind::Other, Error {
                code: ffi::SQLITE_MISUSE,
                message: format!("pos = {} + n = {} > size = {}", self.pos, n, size),
            }));
        }
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe {
            ffi::sqlite3_blob_write(self.blob, mem::transmute(buf.as_ptr()), n, self.pos)
        };
        self.conn.decode_result(rc).map(|_| {
            self.pos += n;
            n as usize
        }).map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

#[allow(unused_must_use)]
impl<'conn> Drop for Blob<'conn> {
    fn drop(&mut self) {
        self.close_();
    }
}

#[cfg(test)]
mod test {
    use std::io::{Read, Write};
    use {Connection, DatabaseName};

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_blob() {
        let db = Connection::open_in_memory().unwrap();
        let sql = "BEGIN;
                CREATE TABLE test (content BLOB);
                INSERT INTO test VALUES (ZEROBLOB(10));
                END;";
        db.execute_batch(sql).unwrap();
        let rowid = db.last_insert_rowid();

        let mut blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, false).unwrap();
        blob.write(b"Clob").unwrap();
        let err = blob.write(b"5678901");
        // writeln!(io::stderr(), "{:?}", err);
        assert!(err.is_err());

        assert!(blob.reopen(rowid).is_ok());
        assert!(blob.close().is_ok());

        blob = db.blob_open(DatabaseName::Main, "test", "content", rowid, true).unwrap();
        let mut bytes = [0u8; 5];
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(0, blob.read(&mut bytes[..]).unwrap());

        assert!(blob.reopen(rowid).is_ok());
        blob.seek(super::SeekFrom::Start(0));
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "with-geo-types-0_7")]
use geo_types_07::{Coordinate, LineString, Point, Rect};

use crate::types::test_type;

#[tokio::test]
async fn test_point_params() {
    test_type(
        "POINT",
        &[
            (Some(Point::new(0.0, 0.0)), "POINT(0, 0)"),
            (Some(Point::new(-3.2, 1.618)), "POINT(-3.2, 1.618)"),
            (None, "NULL"),
        ],
    )
    .await;
}

#[tokio::test]
async fn test_box_params() {
    test_type(
        "BOX",
        &[
            (
                Some(Rect::new(
                    Coordinate { x: -3.2, y: 1.618 },
                    Coordinate {
                        x: 160.0,
                        y: 69701.5615,
                    },
                )),
                "BOX(POINT(160.0, 69701.5615), POINT(-3.2, 1.618))",
            ),
            (None, "NULL"),
        ],
    )
    .await;
}

#[tokio::test]
async fn test_path_params() {
    let points = vec![
        Coordinate { x: 0., y: 0. },
        Coordinate { x: -3.2, y: 1.618 },
        Coordinate {
            x: 160.0,
            y: 69701.5615,
        },
    ];
    test_type(
        "PATH",
        &[
            (
                Some(LineString(points)),
                "path '((0, 0), (-3.2, 1.618), (160.0, 69701.5615))'",
            ),
            (None, "NULL"),
        ],
    )
    .await;
}
<commit_msg>more deprecations<commit_after>#[cfg(feature = "with-geo-types-0_7")]
use geo_types_07::{Coord, LineString, Point, Rect};

use crate::types::test_type;

#[tokio::test]
async fn test_point_params() {
    test_type(
        "POINT",
        &[
            (Some(Point::new(0.0, 0.0)), "POINT(0, 0)"),
            (Some(Point::new(-3.2, 1.618)), "POINT(-3.2, 1.618)"),
            (None, "NULL"),
        ],
    )
    .await;
}

#[tokio::test]
async fn test_box_params() {
    test_type(
        "BOX",
        &[
            (
                Some(Rect::new(
                    Coord { x: -3.2, y: 1.618 },
                    Coord {
                        x: 160.0,
                        y: 69701.5615,
                    },
                )),
                "BOX(POINT(160.0, 69701.5615), POINT(-3.2, 1.618))",
            ),
            (None, "NULL"),
        ],
    )
    .await;
}

#[tokio::test]
async fn test_path_params() {
    let points = vec![
        Coord { x: 0., y: 0. },
        Coord { x: -3.2, y: 1.618 },
        Coord {
            x: 160.0,
            y: 69701.5615,
        },
    ];
    test_type(
        "PATH",
        &[
            (
                Some(LineString(points)),
                "path '((0, 0), (-3.2, 1.618), (160.0, 69701.5615))'",
            ),
            (None, "NULL"),
        ],
    )
    .await;
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::Entry as HashMapEntry;
use std::path::PathBuf;
use std::sync::{Arc, RwLock};
use std::vec::Vec;

use data::{Entry, Hint, SequenceNumber};
use log::{Log, LogWriter};
use stats::Stats;

#[derive(Debug)]
pub struct IndexEntry {
    pub file_id: u32,
    entry_pos: u64,
    pub entry_size: u64,
    sequence: SequenceNumber,
}

struct Index {
    map: HashMap<Vec<u8>, IndexEntry>,
    stats: Stats,
}

impl Index {
    fn new() -> Index {
        Index {
            map: HashMap::new(),
            stats: Stats::new(),
        }
    }

    fn get(&self, key: &[u8]) -> Option<&IndexEntry> {
        self.map.get(key)
    }

    fn insert(&mut self, key: Vec<u8>, index_entry: IndexEntry) -> Option<IndexEntry> {
        self.stats.add_entry(&index_entry);
        self.map.insert(key, index_entry).map(|entry| {
            self.stats.remove_entry(&entry);
            entry
        })
    }

    fn remove(&mut self, key: &[u8]) -> Option<IndexEntry> {
        self.map.remove(key).map(|entry| {
            self.stats.remove_entry(&entry);
            entry
        })
    }

    fn update(&mut self, hint: Hint, file_id: u32) {
        let index_entry = IndexEntry {
            file_id: file_id,
            entry_pos: hint.entry_pos,
            entry_size: hint.entry_size(),
            sequence: hint.sequence,
        };

        match self.map.entry(hint.key.to_vec()) {
            HashMapEntry::Occupied(mut o) => {
                if o.get().sequence <= hint.sequence {
                    self.stats.remove_entry(o.get());
                    if hint.deleted {
                        o.remove();
                    } else {
                        self.stats.add_entry(&index_entry);
                        o.insert(index_entry);
                    }
                } else {
                    self.stats.add_entry(&index_entry);
                    self.stats.remove_entry(&index_entry);
                }
            }
            HashMapEntry::Vacant(e) => {
                if !hint.deleted {
                    self.stats.add_entry(&index_entry);
                    e.insert(index_entry);
                }
            }
        }
    }
}

struct CaskInner {
    current_sequence: SequenceNumber,
    index: Index,
    log: Log,
}

impl CaskInner {
    fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
        self.index.get(key).and_then(|index_entry| {
            let entry = self.log.read_entry(index_entry.file_id, index_entry.entry_pos);
            if entry.deleted {
                warn!("Index pointed to dead entry: Entry {{ key: {:?}, sequence: {} }} at file: \
                       {}",
                      entry.key,
                      entry.sequence,
                      index_entry.file_id);
                None
            } else {
                Some(entry.value.into_owned())
            }
        })
    }

    fn put(&mut self, key: Vec<u8>, value: &[u8]) {
        let index_entry = {
            let entry = Entry::new(self.current_sequence, &*key, value);

            let (file_id, file_pos) = self.log.append_entry(&entry);

            self.current_sequence += 1;

            IndexEntry {
                file_id: file_id,
                entry_pos: file_pos,
                entry_size: entry.size(),
                sequence: entry.sequence,
            }
        };

        self.index.insert(key, index_entry);
    }

    fn delete(&mut self, key: &[u8]) {
        if self.index.remove(key).is_some() {
            let entry = Entry::deleted(self.current_sequence, key);
            let _ = self.log.append_entry(&entry);
            self.current_sequence += 1;
        }
    }
}

#[derive(Clone)]
pub struct Cask {
    path: PathBuf,
    inner: Arc<RwLock<CaskInner>>,
}

impl Cask {
    pub fn open(path: &str, sync: bool) -> Cask {
        info!("Opening database: {:?}", &path);
        let mut log = Log::open(path, sync);
        let mut index = Index::new();

        let mut sequence = 0;

        for file_id in log.files() {
            let mut f = |hint: Hint| {
                if hint.sequence > sequence {
                    sequence = hint.sequence;
                }

                index.update(hint, file_id);
            };

            match log.hints(file_id) {
                Some(hints) => {
                    for hint in hints {
                        f(hint);
                    }
                }
                None => {
                    for hint in log.recreate_hints(file_id) {
                        f(hint);
                    }
                }
            };
        }

        info!("Opened database: {:?}", &path);
        info!("Current sequence number: {:?}", sequence);

        Cask {
            path: log.path.clone(),
            inner: Arc::new(RwLock::new(CaskInner {
                current_sequence: sequence + 1,
                log: log,
                index: index,
            })),
        }
    }

    fn compact_file_aux(&self, file_id: u32) -> Option<u32> {
        if file_id == self.inner.read().unwrap().log.active_file_id {
            return None;
        }

        let hints = {
            self.inner.read().unwrap().log.hints(file_id)
        };

        hints.map(|hints| {
            let new_file_id = {
                self.inner.read().unwrap().log.new_file_id()
            };

            info!("Compacting data file: {} into: {}", file_id, new_file_id);

            let mut log_writer = LogWriter::new(&self.path, new_file_id, false);
            let mut deletes = HashMap::new();

            {
                let inserts = hints.filter(|hint| {
                    let inner = self.inner.read().unwrap();
                    let index_entry = inner.index.get(&*hint.key);

                    if hint.deleted {
                        if index_entry.is_none() {
                            match deletes.entry(hint.key.to_vec()) {
                                HashMapEntry::Occupied(mut o) => {
                                    if *o.get() < hint.sequence {
                                        o.insert(hint.sequence);
                                    }
                                }
                                HashMapEntry::Vacant(e) => {
                                    e.insert(hint.sequence);
                                }
                            }
                        }

                        false

                    } else {
                        index_entry.is_some() && index_entry.unwrap().sequence == hint.sequence
                    }
                });

                for hint in inserts {
                    let log = &self.inner.read().unwrap().log;
                    log_writer.write(&log.read_entry(file_id, hint.entry_pos));
                }
            }

            for (key, sequence) in deletes {
                log_writer.write(&Entry::deleted(sequence, key));
            }

            new_file_id
        })
    }

    pub fn compact_file(&self, file_id: u32) {
        let new_file_id = self.compact_file_aux(file_id);

        if let Some(new_file_id) = new_file_id {
            let hints = {
                self.inner.read().unwrap().log.hints(new_file_id)
            };

            if let Some(hints) = hints {
                for hint in hints {
                    self.inner.write().unwrap().index.update(hint, new_file_id);
                }

                self.inner.write().unwrap().log.swap_file(file_id, new_file_id);

                info!("Finished compacting data file: {} into: {}",
                      file_id,
                      new_file_id);
            };
        }
    }

    pub fn compact(&self) {
        let iter = {
            self.inner
                .read()
                .unwrap()
                .index
                .stats
                .fragmentation()
        };

        for &(file_id, fragmentation) in iter.iter().filter(|e| e.1 >= FRAGMENTATION_THRESHOLD) {

            info!("File {} has fragmentation factor of {}%, adding for compaction",
                  file_id,
                  fragmentation * 100.0);

            self.compact_file(file_id);
        }
    }

    pub fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
        self.inner.read().unwrap().get(key)
    }

    pub fn put(&self, key: Vec<u8>, value: &[u8]) {
        self.inner.write().unwrap().put(key, value)
    }

    pub fn delete(&self, key: &[u8]) {
        self.inner.write().unwrap().delete(key)
    }
}
<commit_msg>start background thread for compaction<commit_after>use std::collections::HashMap;
use std::collections::hash_map::Entry as HashMapEntry;
use std::path::PathBuf;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, RwLock};
use std::thread;
use std::time::Duration;
use std::vec::Vec;

use data::{Entry, Hint, SequenceNumber};
use log::{Log, LogWriter};
use stats::Stats;

const COMPACTION_CHECK_FREQUENCY: u64 = 60;
const FRAGMENTATION_THRESHOLD: f64 = 0.6;

#[derive(Debug)]
pub struct IndexEntry {
    pub file_id: u32,
    entry_pos: u64,
    pub entry_size: u64,
    sequence: SequenceNumber,
}

struct Index {
    map: HashMap<Vec<u8>, IndexEntry>,
    stats: Stats,
}

impl Index {
    fn new() -> Index {
        Index {
            map: HashMap::new(),
            stats: Stats::new(),
        }
    }

    fn get(&self, key: &[u8]) -> Option<&IndexEntry> {
        self.map.get(key)
    }

    fn insert(&mut self, key: Vec<u8>, index_entry: IndexEntry) -> Option<IndexEntry> {
        self.stats.add_entry(&index_entry);
        self.map.insert(key, index_entry).map(|entry| {
            self.stats.remove_entry(&entry);
            entry
        })
    }

    fn remove(&mut self, key: &[u8]) -> Option<IndexEntry> {
        self.map.remove(key).map(|entry| {
            self.stats.remove_entry(&entry);
            entry
        })
    }

    fn update(&mut self, hint: Hint, file_id: u32) {
        let index_entry = IndexEntry {
            file_id: file_id,
            entry_pos: hint.entry_pos,
            entry_size: hint.entry_size(),
            sequence: hint.sequence,
        };

        match self.map.entry(hint.key.to_vec()) {
            HashMapEntry::Occupied(mut o) => {
                if o.get().sequence <= hint.sequence {
                    self.stats.remove_entry(o.get());
                    if hint.deleted {
                        o.remove();
                    } else {
                        self.stats.add_entry(&index_entry);
                        o.insert(index_entry);
                    }
                } else {
                    self.stats.add_entry(&index_entry);
                    self.stats.remove_entry(&index_entry);
                }
            }
            HashMapEntry::Vacant(e) => {
                if !hint.deleted {
                    self.stats.add_entry(&index_entry);
                    e.insert(index_entry);
                }
            }
        }
    }
}

struct CaskInner {
    current_sequence: SequenceNumber,
    index: Index,
    log: Log,
}

impl CaskInner {
    fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
        self.index.get(key).and_then(|index_entry| {
            let entry = self.log.read_entry(index_entry.file_id, index_entry.entry_pos);
            if entry.deleted {
                warn!("Index pointed to dead entry: Entry {{ key: {:?}, sequence: {} }} at file: \
                       {}",
                      entry.key,
                      entry.sequence,
                      index_entry.file_id);
                None
            } else {
                Some(entry.value.into_owned())
            }
        })
    }

    fn put(&mut self, key: Vec<u8>, value: &[u8]) {
        let index_entry = {
            let entry = Entry::new(self.current_sequence, &*key, value);

            let (file_id, file_pos) = self.log.append_entry(&entry);

            self.current_sequence += 1;

            IndexEntry {
                file_id: file_id,
                entry_pos: file_pos,
                entry_size: entry.size(),
                sequence: entry.sequence,
            }
        };

        self.index.insert(key, index_entry);
    }

    fn delete(&mut self, key: &[u8]) {
        if self.index.remove(key).is_some() {
            let entry = Entry::deleted(self.current_sequence, key);
            let _ = self.log.append_entry(&entry);
            self.current_sequence += 1;
        }
    }
}

#[derive(Clone)]
pub struct Cask {
    path: PathBuf,
    dropped: Arc<AtomicBool>,
    inner: Arc<RwLock<CaskInner>>,
}

impl Cask {
    pub fn open(path: &str, sync: bool) -> Cask {
        info!("Opening database: {:?}", &path);
        let mut log = Log::open(path, sync);
        let mut index = Index::new();

        let mut sequence = 0;

        for file_id in log.files() {
            let mut f = |hint: Hint| {
                if hint.sequence > sequence {
                    sequence = hint.sequence;
                }

                index.update(hint, file_id);
            };

            match log.hints(file_id) {
                Some(hints) => {
                    for hint in hints {
                        f(hint);
                    }
                }
                None => {
                    for hint in log.recreate_hints(file_id) {
                        f(hint);
                    }
                }
            };
        }

        info!("Opened database: {:?}", &path);
        info!("Current sequence number: {:?}", sequence);

        let cask = Cask {
            path: log.path.clone(),
            dropped: Arc::new(AtomicBool::new(false)),
            inner: Arc::new(RwLock::new(CaskInner {
                current_sequence: sequence + 1,
                log: log,
                index: index,
            })),
        };

        let caskt = cask.clone();
        thread::spawn(move || {
            loop {
                thread::sleep(Duration::new(COMPACTION_CHECK_FREQUENCY, 0));

                info!("Compaction thread wake up");

                if caskt.dropped.load(Ordering::SeqCst) {
                    info!("Cask has been dropped, background compaction thread is exiting");
                    break;
                }

                caskt.compact();
            };
        });

        cask
    }

    fn compact_file_aux(&self, file_id: u32) -> Option<u32> {
        if file_id == self.inner.read().unwrap().log.active_file_id {
            return None;
        }

        let hints = {
            self.inner.read().unwrap().log.hints(file_id)
        };

        hints.map(|hints| {
            let new_file_id = {
                self.inner.read().unwrap().log.new_file_id()
            };

            info!("Compacting data file: {} into: {}", file_id, new_file_id);

            let mut log_writer = LogWriter::new(&self.path, new_file_id, false);
            let mut deletes = HashMap::new();

            {
                let inserts = hints.filter(|hint| {
                    let inner = self.inner.read().unwrap();
                    let index_entry = inner.index.get(&*hint.key);

                    if hint.deleted {
                        if index_entry.is_none() {
                            match deletes.entry(hint.key.to_vec()) {
                                HashMapEntry::Occupied(mut o) => {
                                    if *o.get() < hint.sequence {
                                        o.insert(hint.sequence);
                                    }
                                }
                                HashMapEntry::Vacant(e) => {
                                    e.insert(hint.sequence);
                                }
                            }
                        }

                        false

                    } else {
                        index_entry.is_some() && index_entry.unwrap().sequence == hint.sequence
                    }
                });

                for hint in inserts {
                    let log = &self.inner.read().unwrap().log;
                    log_writer.write(&log.read_entry(file_id, hint.entry_pos));
                }
            }

            for (key, sequence) in deletes {
                log_writer.write(&Entry::deleted(sequence, key));
            }

            new_file_id
        })
    }

    pub fn compact_file(&self, file_id: u32) {
        let new_file_id = self.compact_file_aux(file_id);

        if let Some(new_file_id) = new_file_id {
            let hints = {
                self.inner.read().unwrap().log.hints(new_file_id)
            };

            if let Some(hints) = hints {
                for hint in hints {
                    self.inner.write().unwrap().index.update(hint, new_file_id);
                }

                self.inner.write().unwrap().log.swap_file(file_id, new_file_id);

                info!("Finished compacting data file: {} into: {}",
                      file_id,
                      new_file_id);
            };
        }
    }

    pub fn compact(&self) {
        let iter = {
            self.inner
                .read()
                .unwrap()
                .index
                .stats
                .fragmentation()
        };

        for &(file_id, fragmentation) in iter.iter().filter(|e| e.1 >= FRAGMENTATION_THRESHOLD) {

            info!("File {} has fragmentation factor of {}%, adding for compaction",
                  file_id,
                  fragmentation * 100.0);

            self.compact_file(file_id);
        }
    }

    pub fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
        self.inner.read().unwrap().get(key)
    }

    pub fn put(&self, key: Vec<u8>, value: &[u8]) {
        self.inner.write().unwrap().put(key, value)
    }

    pub fn delete(&self, key: &[u8]) {
        self.inner.write().unwrap().delete(key)
    }
}

impl Drop for Cask {
    fn drop(&mut self) {
        self.dropped.store(true, Ordering::SeqCst);
    }
}
<|endoftext|>


<commit_before>/// darwin_fd_limit exists to work around an issue where launchctl on macOS
/// defaults the rlimit maxfiles to 256/unlimited. The default soft limit of 256
/// ends up being far too low for our multithreaded scheduler testing, depending
/// on the number of cores available.
///
/// This fixes issue #7772.
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[allow(non_camel_case_types)]
pub unsafe fn raise_fd_limit() {
    use libc;
    use std::cmp;
    use std::io;
    use std::mem::size_of_val;
    use std::ptr::null_mut;

    static CTL_KERN: libc::c_int = 1;
    static KERN_MAXFILESPERPROC: libc::c_int = 29;

    // The strategy here is to fetch the current resource limits, read the
    // kern.maxfilesperproc sysctl value, and bump the soft resource limit for
    // maxfiles up to the sysctl value.

    // Fetch the kern.maxfilesperproc value
    let mut mib: [libc::c_int; 2] = [CTL_KERN, KERN_MAXFILESPERPROC];
    let mut maxfiles: libc::c_int = 0;
    let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t;
    if libc::sysctl(
        &mut mib[0],
        2,
        &mut maxfiles as *mut _ as *mut _,
        &mut size,
        null_mut(),
        0,
    ) != 0
    {
        let err = io::Error::last_os_error();
        panic!("raise_fd_limit: error calling sysctl: {}", err);
    }

    // Fetch the current resource limits
    let mut rlim = libc::rlimit {
        rlim_cur: 0,
        rlim_max: 0,
    };
    if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 {
        let err = io::Error::last_os_error();
        panic!("raise_fd_limit: error calling getrlimit: {}", err);
    }

    // Make sure we're only ever going to increase the rlimit.
    if rlim.rlim_cur < maxfiles as libc::rlim_t {
        // Bump the soft limit to the smaller of kern.maxfilesperproc and the hard limit.
        rlim.rlim_cur = cmp::min(maxfiles as libc::rlim_t, rlim.rlim_max);

        // Set our newly-increased resource limit.
        if libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) != 0 {
            let err = io::Error::last_os_error();
            panic!("raise_fd_limit: error calling setrlimit: {}", err);
        }
    }
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub unsafe fn raise_fd_limit() {}
<commit_msg>bump bootstrap; remove redundant 'use libc;' on macOS.<commit_after>/// darwin_fd_limit exists to work around an issue where launchctl on macOS
/// defaults the rlimit maxfiles to 256/unlimited. The default soft limit of 256
/// ends up being far too low for our multithreaded scheduler testing, depending
/// on the number of cores available.
///
/// This fixes issue #7772.
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[allow(non_camel_case_types)]
pub unsafe fn raise_fd_limit() {
    use std::cmp;
    use std::io;
    use std::mem::size_of_val;
    use std::ptr::null_mut;

    static CTL_KERN: libc::c_int = 1;
    static KERN_MAXFILESPERPROC: libc::c_int = 29;

    // The strategy here is to fetch the current resource limits, read the
    // kern.maxfilesperproc sysctl value, and bump the soft resource limit for
    // maxfiles up to the sysctl value.

    // Fetch the kern.maxfilesperproc value
    let mut mib: [libc::c_int; 2] = [CTL_KERN, KERN_MAXFILESPERPROC];
    let mut maxfiles: libc::c_int = 0;
    let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t;
    if libc::sysctl(
        &mut mib[0],
        2,
        &mut maxfiles as *mut _ as *mut _,
        &mut size,
        null_mut(),
        0,
    ) != 0
    {
        let err = io::Error::last_os_error();
        panic!("raise_fd_limit: error calling sysctl: {}", err);
    }

    // Fetch the current resource limits
    let mut rlim = libc::rlimit {
        rlim_cur: 0,
        rlim_max: 0,
    };
    if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 {
        let err = io::Error::last_os_error();
        panic!("raise_fd_limit: error calling getrlimit: {}", err);
    }

    // Make sure we're only ever going to increase the rlimit.
    if rlim.rlim_cur < maxfiles as libc::rlim_t {
        // Bump the soft limit to the smaller of kern.maxfilesperproc and the hard limit.
        rlim.rlim_cur = cmp::min(maxfiles as libc::rlim_t, rlim.rlim_max);

        // Set our newly-increased resource limit.
        if libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) != 0 {
            let err = io::Error::last_os_error();
            panic!("raise_fd_limit: error calling setrlimit: {}", err);
        }
    }
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub unsafe fn raise_fd_limit() {}
<|endoftext|>


<commit_before>pub type c_char = u8;
pub type c_long = i64;
pub type c_ulong = u64;
pub type wchar_t = u32;
pub type time_t = i64;
pub type suseconds_t = i64;
pub type register_t = i64;

// should be pub(crate), but that requires Rust 1.18.0
cfg_if! {
    if #[cfg(libc_const_size_of)] {
        #[doc(hidden)]
        pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_longlong>() - 1;
    } else {
        #[doc(hidden)]
        pub const _ALIGNBYTES: usize = 8 - 1;
    }
}

pub const MAP_32BIT: ::c_int = 0x00080000;
pub const MINSIGSTKSZ: ::size_t = 4096; // 1024 * 4
<commit_msg>freebsd arm64 ucontext addition.<commit_after>pub type c_char = u8;
pub type c_long = i64;
pub type c_ulong = u64;
pub type wchar_t = u32;
pub type time_t = i64;
pub type suseconds_t = i64;
pub type register_t = i64;

// should be pub(crate), but that requires Rust 1.18.0
cfg_if! {
    if #[cfg(libc_const_size_of)] {
        #[doc(hidden)]
        pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_longlong>() - 1;
    } else {
        #[doc(hidden)]
        pub const _ALIGNBYTES: usize = 8 - 1;
    }
}

s_no_extra_traits! {
    pub struct gpregs {
        pub gp_x: [::register_t; 30],
        pub gp_lr: ::register_t,
        pub gp_sp: ::register_t,
        pub gp_elr: ::register_t,
        pub gp_spsr: u32,
        pub gp_pad: ::c_int,
    }

    pub struct fpregs {
        pub fp_q: u128,
        pub fp_sr: u32,
        pub fp_cr: u32,
        pub fp_flags: ::c_int,
        pub fp_pad: ::c_int,
    }

    pub struct mcontext_t {
        pub mc_gpregs: gpregs,
        pub mc_fpregs: fpregs,
        pub mc_flags: ::c_int,
        pub mc_pad: ::c_int,
        pub mc_spare: [u64; 8],
    }
}

cfg_if! {
    if #[cfg(feature = "extra_traits")] {
        impl PartialEq for gpregs {
            fn eq(&self, other: &gpregs) -> bool {
                self.gp_x.iter().zip(other.gp_x.iter()).all(|(a, b)| a == b) &&
                self.gp_lr == other.gp_lr &&
                self.gp_sp == other.gp_sp &&
                self.gp_elr == other.gp_elr &&
                self.gp_spsr == other.gp_spsr &&
                self.gp_pad == other.gp_pad
            }
        }
        impl Eq for gpregs {}
        impl ::fmt::Debug for gpregs {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("gpregs")
                    .field("gp_x", &self.gp_x)
                    .field("gp_lr", &self.gp_lr)
                    .field("gp_sp", &self.gp_sp)
                    .field("gp_elr", &self.gp_elr)
                    .field("gp_spsr", &self.gp_spsr)
                    .field("gp_pad", &self.gp_pad)
                    .finish()
            }
        }
        impl ::hash::Hash for gpregs {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.gp_x.hash(state);
                self.gp_lr.hash(state);
                self.gp_sp.hash(state);
                self.gp_elr.hash(state);
                self.gp_spsr.hash(state);
                self.gp_pad.hash(state);
            }
        }
        impl PartialEq for fpregs {
            fn eq(&self, other: &fpregs) -> bool {
                self.fp_q == other.fp_q &&
                self.fp_sr == other.fp_sr &&
                self.fp_cr == other.fp_cr &&
                self.fp_flags == other.fp_flags &&
                self.fp_pad == other.fp_pad
            }
        }
        impl Eq for fpregs {}
        impl ::fmt::Debug for fpregs {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("fpregs")
                    .field("fp_q", &self.fp_q)
                    .field("fp_sr", &self.fp_sr)
                    .field("fp_cr", &self.fp_cr)
                    .field("fp_flags", &self.fp_flags)
                    .field("fp_pad", &self.fp_pad)
                    .finish()
            }
        }
        impl ::hash::Hash for fpregs {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.fp_q.hash(state);
                self.fp_sr.hash(state);
                self.fp_cr.hash(state);
                self.fp_flags.hash(state);
                self.fp_pad.hash(state);
            }
        }
        impl PartialEq for mcontext_t {
            fn eq(&self, other: &mcontext_t) -> bool {
                self.mc_gpregs == other.mc_gpregs &&
                self.mc_fpregs == other.mc_fpregs &&
                self.mc_flags == other.mc_flags &&
                self.mc_pad == other.mc_pad &&
                self.mc_spare.iter().zip(other.mc_spare.iter()).all(|(a, b)| a == b)
            }
        }
        impl Eq for mcontext_t {}
        impl ::fmt::Debug for mcontext_t {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("mcontext_t")
                    .field("mc_gpregs", &self.mc_gpregs)
                    .field("mc_fpregs", &self.mc_fpregs)
                    .field("mc_flags", &self.mc_flags)
                    .field("mc_pad", &self.mc_pad)
                    .field("mc_spare", &self.mc_spare)
                    .finish()
            }
        }
        impl ::hash::Hash for mcontext_t {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.mc_gpregs.hash(state);
                self.mc_fpregs.hash(state);
                self.mc_flags.hash(state);
                self.mc_pad.hash(state);
                self.mc_spare.hash(state);
            }
        }
    }
}

pub const MAP_32BIT: ::c_int = 0x00080000;
pub const MINSIGSTKSZ: ::size_t = 4096; // 1024 * 4
<|endoftext|>