<commit_before>use std::ops::Deref;
use std::borrow::{Cow, Borrow};
use std::hash::{Hash, Hasher};

///An owned string that may be UTF-8 encoded.
pub type MaybeUtf8Owned = MaybeUtf8<String, Vec<u8>>;
///A slice of a string that may be UTF-8 encoded.
pub type MaybeUtf8Slice<'a> = MaybeUtf8<&'a str, &'a [u8]>;

///String data that may or may not be UTF-8 encoded.
#[derive(Debug, Clone)]
pub enum MaybeUtf8<S, V> {
    ///A UTF-8 encoded string.
    Utf8(S),
    ///A non-UTF-8 string.
    NotUtf8(V)
}

impl<S, V> MaybeUtf8<S, V> {
    ///Produce a slice of this string.
    pub fn as_slice<Sref: ?Sized, Vref: ?Sized>(&self) -> MaybeUtf8<&Sref, &Vref> where S: AsRef<Sref>, V: AsRef<Vref> {
        match *self {
            MaybeUtf8::Utf8(ref s) => MaybeUtf8::Utf8(s.as_ref()),
            MaybeUtf8::NotUtf8(ref v) => MaybeUtf8::NotUtf8(v.as_ref())
        }
    }

    ///Borrow the string if it's encoded as valid UTF-8.
    pub fn as_utf8<'a>(&'a self) -> Option<&'a str> where S: AsRef<str> {
        match *self {
            MaybeUtf8::Utf8(ref s) => Some(s.as_ref()),
            MaybeUtf8::NotUtf8(_) => None
        }
    }

    ///Borrow the string if it's encoded as valid UTF-8, or make a lossy conversion.
    pub fn as_utf8_lossy<'a>(&'a self) -> Cow<'a, str> where S: AsRef<str>, V: AsRef<[u8]> {
        match *self {
            MaybeUtf8::Utf8(ref s) => s.as_ref().into(),
            MaybeUtf8::NotUtf8(ref v) => String::from_utf8_lossy(v.as_ref())
        }
    }

    ///Borrow the string as a slice of bytes.
    pub fn as_bytes(&self) -> &[u8] where S: AsRef<[u8]>, V: AsRef<[u8]> {
        match *self {
            MaybeUtf8::Utf8(ref s) => s.as_ref(),
            MaybeUtf8::NotUtf8(ref v) => v.as_ref()
        }
    }
}

impl<V> From<String> for MaybeUtf8<String, V> {
    fn from(string: String) -> MaybeUtf8<String, V> {
        MaybeUtf8::Utf8(string)
    }
}

impl<'a, V> From<&'a str> for MaybeUtf8<&'a str, V> {
    fn from(string: &'a str) -> MaybeUtf8<&'a str, V> {
        MaybeUtf8::Utf8(string)
    }
}

impl From<Vec<u8>> for MaybeUtf8<String, Vec<u8>> {
    fn from(bytes: Vec<u8>) -> MaybeUtf8<String, Vec<u8>> {
        match String::from_utf8(bytes) {
            Ok(string) => MaybeUtf8::Utf8(string),
            Err(e) => MaybeUtf8::NotUtf8(e.into_bytes())
        }
    }
}

impl<S: AsRef<[u8]>, V: AsRef<[u8]>> AsRef<[u8]> for MaybeUtf8<S, V> {
    fn as_ref(&self) -> &[u8] {
        match *self {
            MaybeUtf8::Utf8(ref s) => s.as_ref(),
            MaybeUtf8::NotUtf8(ref v) => v.as_ref()
        }
    }
}

impl<S: AsRef<[u8]>, V: AsRef<[u8]>> Borrow<[u8]> for MaybeUtf8<S, V> {
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

impl<S: AsRef<[u8]>, V: AsRef<[u8]>> PartialEq for MaybeUtf8<S, V> {
    fn eq(&self, other: &MaybeUtf8<S, V>) -> bool {
        self.as_ref().eq(other.as_ref())
    }
}

impl<S: AsRef<[u8]>, V: AsRef<[u8]>> Eq for MaybeUtf8<S, V> {}

impl<S: AsRef<[u8]>, V: AsRef<[u8]>> Hash for MaybeUtf8<S, V> {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.as_ref().hash(hasher)
    }
}

impl<S: Into<String>, V: Into<Vec<u8>>> Into<String> for MaybeUtf8<S, V> {
    fn into(self) -> String {
        match self {
            MaybeUtf8::Utf8(s) => s.into(),
            MaybeUtf8::NotUtf8(v) => {
                let bytes = v.into();
                match String::from_utf8_lossy(&bytes) {
                    Cow::Borrowed(_) => unsafe { String::from_utf8_unchecked(bytes) },
                    Cow::Owned(s) => s
                }
            }
        }
    }
}

impl<S: Into<Vec<u8>>, V: Into<Vec<u8>>> Into<Vec<u8>> for MaybeUtf8<S, V> {
    fn into(self) -> Vec<u8> {
        match self {
            MaybeUtf8::Utf8(s) => s.into(),
            MaybeUtf8::NotUtf8(v) => v.into()
        }
    }
}

impl<S: AsRef<[u8]>, V: AsRef<[u8]>> Deref for MaybeUtf8<S, V> {
    type Target=[u8];

    fn deref(&self) -> &[u8] {
        self.as_ref()
    }
}<commit_msg>Implement extension methods for MaybeUtf8<commit_after>use std::ops::Deref;
use std::borrow::{Cow, Borrow};
use std::hash::{Hash, Hasher};

///An owned string that may be UTF-8 encoded.
pub type MaybeUtf8Owned = MaybeUtf8<String, Vec<u8>>;
///A slice of a string that may be UTF-8 encoded.
pub type MaybeUtf8Slice<'a> = MaybeUtf8<&'a str, &'a [u8]>;

///String data that may or may not be UTF-8 encoded.
#[derive(Debug, Clone)]
pub enum MaybeUtf8<S, V> {
    ///A UTF-8 encoded string.
    Utf8(S),
    ///A non-UTF-8 string.
    NotUtf8(V)
}

impl<S, V> MaybeUtf8<S, V> {
    ///Produce a slice of this string.
    pub fn as_slice<Sref: ?Sized, Vref: ?Sized>(&self) -> MaybeUtf8<&Sref, &Vref> where S: AsRef<Sref>, V: AsRef<Vref> {
        match *self {
            MaybeUtf8::Utf8(ref s) => MaybeUtf8::Utf8(s.as_ref()),
            MaybeUtf8::NotUtf8(ref v) => MaybeUtf8::NotUtf8(v.as_ref())
        }
    }

    ///Borrow the string if it's encoded as valid UTF-8.
    pub fn as_utf8<'a>(&'a self) -> Option<&'a str> where S: AsRef<str> {
        match *self {
            MaybeUtf8::Utf8(ref s) => Some(s.as_ref()),
            MaybeUtf8::NotUtf8(_) => None
        }
    }

    ///Borrow the string if it's encoded as valid UTF-8, or make a lossy conversion.
    pub fn as_utf8_lossy<'a>(&'a self) -> Cow<'a, str> where S: AsRef<str>, V: AsRef<[u8]> {
        match *self {
            MaybeUtf8::Utf8(ref s) => s.as_ref().into(),
            MaybeUtf8::NotUtf8(ref v) => String::from_utf8_lossy(v.as_ref())
        }
    }

    ///Borrow the string as a slice of bytes.
    pub fn as_bytes(&self) -> &[u8] where S: AsRef<[u8]>, V: AsRef<[u8]> {
        match *self {
            MaybeUtf8::Utf8(ref s) => s.as_ref(),
            MaybeUtf8::NotUtf8(ref v) => v.as_ref()
        }
    }
}

impl MaybeUtf8<String, Vec<u8>> {
    ///Push a single `char` to the end of the string.
    pub fn push_char(&mut self, c: char) {
        match *self {
            MaybeUtf8::Utf8(ref mut s) => s.push(c),
            MaybeUtf8::NotUtf8(ref mut v) => {
                //Do some witchcraft until encode_utf8 becomes a thing.
                let string: &mut String = unsafe { ::std::mem::transmute(v) };
                string.push(c);
            }
        }
    }

    ///Extend the string.
    pub fn push_str(&mut self, string: &str) {
        match *self {
            MaybeUtf8::Utf8(ref mut s) => s.push_str(string),
            MaybeUtf8::NotUtf8(ref mut v) => v.extend(string.as_bytes().iter().cloned())
        }
    }

    ///Push a number of bytes to the string. The strings UTF-8 compatibility
    ///may change.
    pub fn push_bytes(&mut self, bytes: &[u8]) {
        match ::std::str::from_utf8(bytes) {
            Ok(string) => self.push_str(string),
            Err(_) => {
                let mut v = MaybeUtf8::NotUtf8(vec![]);
                ::std::mem::swap(self, &mut v);
                let mut v: Vec<u8> = v.into();
                v.extend(bytes.iter().cloned());
                *self = v.into();
            }
        }
    }
}

impl<V> From<String> for MaybeUtf8<String, V> {
    fn from(string: String) -> MaybeUtf8<String, V> {
        MaybeUtf8::Utf8(string)
    }
}

impl<'a, V> From<&'a str> for MaybeUtf8<&'a str, V> {
    fn from(string: &'a str) -> MaybeUtf8<&'a str, V> {
        MaybeUtf8::Utf8(string)
    }
}

impl From<Vec<u8>> for MaybeUtf8<String, Vec<u8>> {
    fn from(bytes: Vec<u8>) -> MaybeUtf8<String, Vec<u8>> {
        match String::from_utf8(bytes) {
            Ok(string) => MaybeUtf8::Utf8(string),
            Err(e) => MaybeUtf8::NotUtf8(e.into_bytes())
        }
    }
}

impl<S: AsRef<[u8]>, V: AsRef<[u8]>> AsRef<[u8]> for MaybeUtf8<S, V> {
    fn as_ref(&self) -> &[u8] {
        match *self {
            MaybeUtf8::Utf8(ref s) => s.as_ref(),
            MaybeUtf8::NotUtf8(ref v) => v.as_ref()
        }
    }
}

impl<S: AsRef<[u8]>, V: AsRef<[u8]>> Borrow<[u8]> for MaybeUtf8<S, V> {
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

impl<S: AsRef<[u8]>, V: AsRef<[u8]>> PartialEq for MaybeUtf8<S, V> {
    fn eq(&self, other: &MaybeUtf8<S, V>) -> bool {
        self.as_ref().eq(other.as_ref())
    }
}

impl<S: AsRef<[u8]>, V: AsRef<[u8]>> Eq for MaybeUtf8<S, V> {}

impl<S: AsRef<[u8]>, V: AsRef<[u8]>> Hash for MaybeUtf8<S, V> {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.as_ref().hash(hasher)
    }
}

impl<S: Into<String>, V: Into<Vec<u8>>> Into<String> for MaybeUtf8<S, V> {
    fn into(self) -> String {
        match self {
            MaybeUtf8::Utf8(s) => s.into(),
            MaybeUtf8::NotUtf8(v) => {
                let bytes = v.into();
                match String::from_utf8_lossy(&bytes) {
                    Cow::Borrowed(_) => unsafe { String::from_utf8_unchecked(bytes) },
                    Cow::Owned(s) => s
                }
            }
        }
    }
}

impl<S: Into<Vec<u8>>, V: Into<Vec<u8>>> Into<Vec<u8>> for MaybeUtf8<S, V> {
    fn into(self) -> Vec<u8> {
        match self {
            MaybeUtf8::Utf8(s) => s.into(),
            MaybeUtf8::NotUtf8(v) => v.into()
        }
    }
}

impl<S: AsRef<[u8]>, V: AsRef<[u8]>> Deref for MaybeUtf8<S, V> {
    type Target=[u8];

    fn deref(&self) -> &[u8] {
        self.as_ref()
    }
}<|endoftext|>


<commit_before>#![feature(inner_deref)]

extern crate cargo_metadata;

use std::path::{PathBuf, Path};
use std::io::{self, Write};
use std::process::Command;
use std::fs::{self, File};

const CARGO_MIRI_HELP: &str = r#"Interprets bin crates

Usage:
    cargo miri [subcommand] [options] [--] [<opts>...]

Subcommands:
    run                      Run binaries (default)
    test                     Run tests
    setup                    Only perform automatic setup, but without asking questions (for getting a proper libstd)

Common options:
    -h, --help               Print this message
    --features               Features to compile for the package
    -V, --version            Print version info and exit

Other options are the same as `cargo rustc`.

The feature `cargo-miri` is automatically defined for convenience. You can use
it to configure the resource limits

    #![cfg_attr(feature = "cargo-miri", memory_size = 42)]

available resource limits are `memory_size`, `step_limit`, `stack_limit`
"#;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum MiriCommand {
    Run,
    Test,
    Setup,
}

fn show_help() {
    println!("{}", CARGO_MIRI_HELP);
}

fn show_version() {
    println!("miri {} ({} {})",
        env!("CARGO_PKG_VERSION"), env!("VERGEN_SHA_SHORT"), env!("VERGEN_COMMIT_DATE"));
}

fn show_error(msg: String) -> ! {
    eprintln!("fatal error: {}", msg);
    std::process::exit(1)
}

fn list_targets(mut args: impl Iterator<Item=String>) -> impl Iterator<Item=cargo_metadata::Target> {
    // We need to get the manifest, and then the metadata, to enumerate targets.
    let manifest_path_arg = args.find(|val| {
        val.starts_with("--manifest-path=")
    });

    let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(
        manifest_path_arg.as_ref().map(AsRef::as_ref),
    )
    {
        metadata
    } else {
        show_error(format!("error: Could not obtain cargo metadata."));
    };

    let manifest_path = manifest_path_arg.map(|arg| {
        PathBuf::from(Path::new(&arg["--manifest-path=".len()..]))
    });

    let current_dir = std::env::current_dir();

    let package_index = metadata
        .packages
        .iter()
        .position(|package| {
            let package_manifest_path = Path::new(&package.manifest_path);
            if let Some(ref manifest_path) = manifest_path {
                package_manifest_path == manifest_path
            } else {
                let current_dir = current_dir.as_ref().expect(
                    "could not read current directory",
                );
                let package_manifest_directory = package_manifest_path.parent().expect(
                    "could not find parent directory of package manifest",
                );
                package_manifest_directory == current_dir
            }
        })
        .expect("could not find matching package");
    let package = metadata.packages.remove(package_index);

    // Finally we got the list of targets to build
    package.targets.into_iter()
}

fn ask(question: &str) {
    let mut buf = String::new();
    print!("{} [Y/n] ", question);
    io::stdout().flush().unwrap();
    io::stdin().read_line(&mut buf).unwrap();
    match buf.trim().to_lowercase().as_ref() {
        "" | "y" | "yes" => {}, // proceed
        "n" | "no" => show_error(format!("Aborting as per your request")),
        a => show_error(format!("I do not understand `{}`", a))
    };
}

/// Perform the setup requires to make `cargo miri` work: Getting a custom-built libstd. Then sets MIRI_SYSROOT.
/// Skipped if MIRI_SYSROOT is already set, in that case we expect the user has done all this already.
fn setup(ask_user: bool) {
    if std::env::var("MIRI_SYSROOT").is_ok() {
        return;
    }

    // First, we need xargo
    if Command::new("xargo").arg("--version").output().is_err()
    {
        if ask_user {
            ask("It seems you do not have xargo installed. I will run `cargo install xargo`. Proceed?");
        } else {
            println!("Installing xargo: `cargo install xargo`");
        }
        if !Command::new("cargo").args(&["install", "xargo"]).status().unwrap().success() {
            show_error(format!("Failed to install xargo"));
        }
    }

    // Then, we also need rust-src.  Let's see if it is already installed.
    let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout;
    let sysroot = std::str::from_utf8(&sysroot[..]).unwrap();
    let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src");
    if !src.exists() {
        if ask_user {
            ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?");
        } else {
            println!("Installing rust-src component: `rustup component add rust-src`");
        }
        if !Command::new("rustup").args(&["component", "add", "rust-src"]).status().unwrap().success() {
            show_error(format!("Failed to install rust-src component"));
        }
    }

    // Next, we need our own libstd. We will do this work in whatever is a good cache dir for this platform.
    let dirs = directories::ProjectDirs::from("miri", "miri", "miri").unwrap();
    let dir = dirs.cache_dir();
    if !dir.exists() {
        fs::create_dir_all(&dir).unwrap();
    }
    // The interesting bit: Xargo.toml
    File::create(dir.join("Xargo.toml")).unwrap()
        .write_all(br#"
[dependencies.std]
features = ["panic_unwind"]

[dependencies.test]
stage = 1
        "#).unwrap();
    // The boring bits: A dummy project for xargo
    File::create(dir.join("Cargo.toml")).unwrap()
        .write_all(br#"
[package]
name = "miri-xargo"
description = "A dummy project for building libstd with xargo."
version = "0.0.0"

[lib]
path = "lib.rs"
        "#).unwrap();
    File::create(dir.join("lib.rs")).unwrap();
    // Run xargo
    if !Command::new("xargo").arg("build").arg("-q")
        .current_dir(&dir)
        .env("RUSTFLAGS", miri::miri_default_args().join(" "))
        .env("XARGO_HOME", dir.to_str().unwrap())
        .status().unwrap().success()
    {
        show_error(format!("Failed to run xargo"));
    }

    // That should be it!
    let sysroot = dir.join("HOST");
    std::env::set_var("MIRI_SYSROOT", &sysroot);
    if !ask_user {
        println!("A libstd for miri is now available in `{}`", sysroot.display());
    }
}

fn main() {
    // Check for version and help flags even when invoked as 'cargo-miri'
    if std::env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }
    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    if let Some("miri") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
        // this arm is when `cargo miri` is called.  We call `cargo rustc` for
        // each applicable target, but with the RUSTC env var set to the `cargo-miri`
        // binary so that we come back in the other branch, and dispatch
        // the invocations to rustc and miri, respectively.

        let (subcommand, skip) = match std::env::args().nth(2).deref() {
            Some("test") => (MiriCommand::Test, 3),
            Some("run") => (MiriCommand::Run, 3),
            Some("setup") => (MiriCommand::Setup, 3),
            // Default command, if there is an option or nothing
            Some(s) if s.starts_with("-") => (MiriCommand::Run, 2),
            None => (MiriCommand::Run, 2),
            // Unvalid command
            Some(s) => {
                show_error(format!("Unknown command `{}`", s))
            }
        };

        // We always setup
        let ask = subcommand != MiriCommand::Setup;
        setup(ask);
        if subcommand == MiriCommand::Setup {
            // Stop here.
            return;
        }

        // Now run the command.
        for target in list_targets(std::env::args().skip(skip)) {
            let args = std::env::args().skip(skip);
            let kind = target.kind.get(0).expect(
                "badly formatted cargo metadata: target::kind is an empty array",
            );
            match (subcommand, &kind[..]) {
                (MiriCommand::Test, "test") => {
                    // For test binaries we call `cargo rustc --test target -- <rustc args>`
                    if let Err(code) = process(
                        vec!["--test".to_string(), target.name].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                (MiriCommand::Test, "lib") => {
                    // For libraries we call `cargo rustc -- --test <rustc args>`
                    // Notice now that `--test` is a rustc arg rather than a cargo arg. This tells
                    // rustc to build a test harness which calls all #[test] functions. We don't
                    // use the harness since we execute each #[test] function's MIR ourselves before
                    // compilation even completes, but this option is necessary to build the library.
                    if let Err(code) = process(
                        vec!["--".to_string(), "--test".to_string()].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                (MiriCommand::Run, "bin") => {
                    // For ordinary binaries we call `cargo rustc --bin target -- <rustc args>`
                    if let Err(code) = process(
                        vec!["--bin".to_string(), target.name].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                _ => {}
            }
        }
    } else {
        // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC` env var set to itself:
        // Dependencies get dispatched to rustc, the final test/binary to miri.

        let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
        let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
        let sys_root = if let Ok(sysroot) = ::std::env::var("MIRI_SYSROOT") {
            sysroot
        } else if let (Some(home), Some(toolchain)) = (home, toolchain) {
            format!("{}/toolchains/{}", home, toolchain)
        } else {
            option_env!("RUST_SYSROOT")
                .map(|s| s.to_owned())
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| s.trim().to_owned())
                })
                .expect("need to specify RUST_SYSROOT env var during miri compilation, or use rustup or multirust")
        };

        // this conditional check for the --sysroot flag is there so users can call `cargo-miri` directly
        // without having to pass --sysroot or anything
        let mut args: Vec<String> = if std::env::args().any(|s| s == "--sysroot") {
            std::env::args().skip(1).collect()
        } else {
            std::env::args()
                .skip(1)
                .chain(Some("--sysroot".to_owned()))
                .chain(Some(sys_root))
                .collect()
        };
        args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string));

        // this check ensures that dependencies are built but not interpreted and the final crate is
        // interpreted but not built
        let miri_enabled = std::env::args().any(|s| s == "--emit=dep-info,metadata");

        let mut command = if miri_enabled {
            let mut path = std::env::current_exe().expect("current executable path invalid");
            path.set_file_name("miri");
            Command::new(path)
        } else {
            Command::new("rustc")
        };

        args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]);

        match command.args(&args).status() {
            Ok(exit) => {
                if !exit.success() {
                    std::process::exit(exit.code().unwrap_or(42));
                }
            }
            Err(ref e) if miri_enabled => panic!("error during miri run: {:?}", e),
            Err(ref e) => panic!("error during rustc call: {:?}", e),
        }
    }
}

fn process<I>(old_args: I) -> Result<(), i32>
where
    I: Iterator<Item = String>,
{
    let mut args = vec!["rustc".to_owned()];

    let mut found_dashes = false;
    for arg in old_args {
        found_dashes |= arg == "--";
        args.push(arg);
    }
    if !found_dashes {
        args.push("--".to_owned());
    }
    args.push("--emit=dep-info,metadata".to_owned());
    args.push("--cfg".to_owned());
    args.push(r#"feature="cargo-miri""#.to_owned());

    let path = std::env::current_exe().expect("current executable path invalid");
    let exit_status = std::process::Command::new("cargo")
        .args(&args)
        .env("RUSTC", path)
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}
<commit_msg>build libstd with minimal features<commit_after>#![feature(inner_deref)]

extern crate cargo_metadata;

use std::path::{PathBuf, Path};
use std::io::{self, Write};
use std::process::Command;
use std::fs::{self, File};

const CARGO_MIRI_HELP: &str = r#"Interprets bin crates

Usage:
    cargo miri [subcommand] [options] [--] [<opts>...]

Subcommands:
    run                      Run binaries (default)
    test                     Run tests
    setup                    Only perform automatic setup, but without asking questions (for getting a proper libstd)

Common options:
    -h, --help               Print this message
    --features               Features to compile for the package
    -V, --version            Print version info and exit

Other options are the same as `cargo rustc`.

The feature `cargo-miri` is automatically defined for convenience. You can use
it to configure the resource limits

    #![cfg_attr(feature = "cargo-miri", memory_size = 42)]

available resource limits are `memory_size`, `step_limit`, `stack_limit`
"#;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum MiriCommand {
    Run,
    Test,
    Setup,
}

fn show_help() {
    println!("{}", CARGO_MIRI_HELP);
}

fn show_version() {
    println!("miri {} ({} {})",
        env!("CARGO_PKG_VERSION"), env!("VERGEN_SHA_SHORT"), env!("VERGEN_COMMIT_DATE"));
}

fn show_error(msg: String) -> ! {
    eprintln!("fatal error: {}", msg);
    std::process::exit(1)
}

fn list_targets(mut args: impl Iterator<Item=String>) -> impl Iterator<Item=cargo_metadata::Target> {
    // We need to get the manifest, and then the metadata, to enumerate targets.
    let manifest_path_arg = args.find(|val| {
        val.starts_with("--manifest-path=")
    });

    let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(
        manifest_path_arg.as_ref().map(AsRef::as_ref),
    )
    {
        metadata
    } else {
        show_error(format!("error: Could not obtain cargo metadata."));
    };

    let manifest_path = manifest_path_arg.map(|arg| {
        PathBuf::from(Path::new(&arg["--manifest-path=".len()..]))
    });

    let current_dir = std::env::current_dir();

    let package_index = metadata
        .packages
        .iter()
        .position(|package| {
            let package_manifest_path = Path::new(&package.manifest_path);
            if let Some(ref manifest_path) = manifest_path {
                package_manifest_path == manifest_path
            } else {
                let current_dir = current_dir.as_ref().expect(
                    "could not read current directory",
                );
                let package_manifest_directory = package_manifest_path.parent().expect(
                    "could not find parent directory of package manifest",
                );
                package_manifest_directory == current_dir
            }
        })
        .expect("could not find matching package");
    let package = metadata.packages.remove(package_index);

    // Finally we got the list of targets to build
    package.targets.into_iter()
}

fn ask(question: &str) {
    let mut buf = String::new();
    print!("{} [Y/n] ", question);
    io::stdout().flush().unwrap();
    io::stdin().read_line(&mut buf).unwrap();
    match buf.trim().to_lowercase().as_ref() {
        "" | "y" | "yes" => {}, // proceed
        "n" | "no" => show_error(format!("Aborting as per your request")),
        a => show_error(format!("I do not understand `{}`", a))
    };
}

/// Perform the setup requires to make `cargo miri` work: Getting a custom-built libstd. Then sets MIRI_SYSROOT.
/// Skipped if MIRI_SYSROOT is already set, in that case we expect the user has done all this already.
fn setup(ask_user: bool) {
    if std::env::var("MIRI_SYSROOT").is_ok() {
        return;
    }

    // First, we need xargo
    if Command::new("xargo").arg("--version").output().is_err()
    {
        if ask_user {
            ask("It seems you do not have xargo installed. I will run `cargo install xargo`. Proceed?");
        } else {
            println!("Installing xargo: `cargo install xargo`");
        }
        if !Command::new("cargo").args(&["install", "xargo"]).status().unwrap().success() {
            show_error(format!("Failed to install xargo"));
        }
    }

    // Then, we also need rust-src.  Let's see if it is already installed.
    let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout;
    let sysroot = std::str::from_utf8(&sysroot[..]).unwrap();
    let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src");
    if !src.exists() {
        if ask_user {
            ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?");
        } else {
            println!("Installing rust-src component: `rustup component add rust-src`");
        }
        if !Command::new("rustup").args(&["component", "add", "rust-src"]).status().unwrap().success() {
            show_error(format!("Failed to install rust-src component"));
        }
    }

    // Next, we need our own libstd. We will do this work in whatever is a good cache dir for this platform.
    let dirs = directories::ProjectDirs::from("miri", "miri", "miri").unwrap();
    let dir = dirs.cache_dir();
    if !dir.exists() {
        fs::create_dir_all(&dir).unwrap();
    }
    // The interesting bit: Xargo.toml
    File::create(dir.join("Xargo.toml")).unwrap()
        .write_all(br#"
[dependencies.std]
default_features = false
# We need the `panic_unwind` feature because we use the `unwind` panic strategy.
# Using `abort` works for libstd, but then libtest will not compile.
features = ["panic_unwind"]

[dependencies.test]
stage = 1
        "#).unwrap();
    // The boring bits: A dummy project for xargo
    File::create(dir.join("Cargo.toml")).unwrap()
        .write_all(br#"
[package]
name = "miri-xargo"
description = "A dummy project for building libstd with xargo."
version = "0.0.0"

[lib]
path = "lib.rs"
        "#).unwrap();
    File::create(dir.join("lib.rs")).unwrap();
    // Run xargo
    if !Command::new("xargo").arg("build").arg("-q")
        .current_dir(&dir)
        .env("RUSTFLAGS", miri::miri_default_args().join(" "))
        .env("XARGO_HOME", dir.to_str().unwrap())
        .status().unwrap().success()
    {
        show_error(format!("Failed to run xargo"));
    }

    // That should be it!
    let sysroot = dir.join("HOST");
    std::env::set_var("MIRI_SYSROOT", &sysroot);
    if !ask_user {
        println!("A libstd for miri is now available in `{}`", sysroot.display());
    }
}

fn main() {
    // Check for version and help flags even when invoked as 'cargo-miri'
    if std::env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }
    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    if let Some("miri") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
        // this arm is when `cargo miri` is called.  We call `cargo rustc` for
        // each applicable target, but with the RUSTC env var set to the `cargo-miri`
        // binary so that we come back in the other branch, and dispatch
        // the invocations to rustc and miri, respectively.

        let (subcommand, skip) = match std::env::args().nth(2).deref() {
            Some("test") => (MiriCommand::Test, 3),
            Some("run") => (MiriCommand::Run, 3),
            Some("setup") => (MiriCommand::Setup, 3),
            // Default command, if there is an option or nothing
            Some(s) if s.starts_with("-") => (MiriCommand::Run, 2),
            None => (MiriCommand::Run, 2),
            // Unvalid command
            Some(s) => {
                show_error(format!("Unknown command `{}`", s))
            }
        };

        // We always setup
        let ask = subcommand != MiriCommand::Setup;
        setup(ask);
        if subcommand == MiriCommand::Setup {
            // Stop here.
            return;
        }

        // Now run the command.
        for target in list_targets(std::env::args().skip(skip)) {
            let args = std::env::args().skip(skip);
            let kind = target.kind.get(0).expect(
                "badly formatted cargo metadata: target::kind is an empty array",
            );
            match (subcommand, &kind[..]) {
                (MiriCommand::Test, "test") => {
                    // For test binaries we call `cargo rustc --test target -- <rustc args>`
                    if let Err(code) = process(
                        vec!["--test".to_string(), target.name].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                (MiriCommand::Test, "lib") => {
                    // For libraries we call `cargo rustc -- --test <rustc args>`
                    // Notice now that `--test` is a rustc arg rather than a cargo arg. This tells
                    // rustc to build a test harness which calls all #[test] functions. We don't
                    // use the harness since we execute each #[test] function's MIR ourselves before
                    // compilation even completes, but this option is necessary to build the library.
                    if let Err(code) = process(
                        vec!["--".to_string(), "--test".to_string()].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                (MiriCommand::Run, "bin") => {
                    // For ordinary binaries we call `cargo rustc --bin target -- <rustc args>`
                    if let Err(code) = process(
                        vec!["--bin".to_string(), target.name].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                _ => {}
            }
        }
    } else {
        // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC` env var set to itself:
        // Dependencies get dispatched to rustc, the final test/binary to miri.

        let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
        let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
        let sys_root = if let Ok(sysroot) = ::std::env::var("MIRI_SYSROOT") {
            sysroot
        } else if let (Some(home), Some(toolchain)) = (home, toolchain) {
            format!("{}/toolchains/{}", home, toolchain)
        } else {
            option_env!("RUST_SYSROOT")
                .map(|s| s.to_owned())
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| s.trim().to_owned())
                })
                .expect("need to specify RUST_SYSROOT env var during miri compilation, or use rustup or multirust")
        };

        // this conditional check for the --sysroot flag is there so users can call `cargo-miri` directly
        // without having to pass --sysroot or anything
        let mut args: Vec<String> = if std::env::args().any(|s| s == "--sysroot") {
            std::env::args().skip(1).collect()
        } else {
            std::env::args()
                .skip(1)
                .chain(Some("--sysroot".to_owned()))
                .chain(Some(sys_root))
                .collect()
        };
        args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string));

        // this check ensures that dependencies are built but not interpreted and the final crate is
        // interpreted but not built
        let miri_enabled = std::env::args().any(|s| s == "--emit=dep-info,metadata");

        let mut command = if miri_enabled {
            let mut path = std::env::current_exe().expect("current executable path invalid");
            path.set_file_name("miri");
            Command::new(path)
        } else {
            Command::new("rustc")
        };

        args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]);

        match command.args(&args).status() {
            Ok(exit) => {
                if !exit.success() {
                    std::process::exit(exit.code().unwrap_or(42));
                }
            }
            Err(ref e) if miri_enabled => panic!("error during miri run: {:?}", e),
            Err(ref e) => panic!("error during rustc call: {:?}", e),
        }
    }
}

fn process<I>(old_args: I) -> Result<(), i32>
where
    I: Iterator<Item = String>,
{
    let mut args = vec!["rustc".to_owned()];

    let mut found_dashes = false;
    for arg in old_args {
        found_dashes |= arg == "--";
        args.push(arg);
    }
    if !found_dashes {
        args.push("--".to_owned());
    }
    args.push("--emit=dep-info,metadata".to_owned());
    args.push("--cfg".to_owned());
    args.push(r#"feature="cargo-miri""#.to_owned());

    let path = std::env::current_exe().expect("current executable path invalid");
    let exit_status = std::process::Command::new("cargo")
        .args(&args)
        .env("RUSTC", path)
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}
<|endoftext|>


<commit_before>
/// Represents a position on the board.
/// It starts counting from 1, so that 0 can be used
/// to represent the border.
#[derive(Clone, PartialEq, Eq)]
pub struct Position {
    row: u8,
    column: u8
}

impl Position {
    /// Create a new board position with the given row and column
    pub fn new(r: u8, c: u8) -> Position {
        Position { row: r, column: c }
    }

    /// Generate all positions on the board
    /// (excluding the border)
    pub fn generate_positions(board_size: u8) -> Vec<Position> {
        (0us..(board_size as usize * board_size as usize))
            .map(|index| Position::from_linear_index(board_size, index))
            .collect()
    }

    /// Creates a new position from a linear index on the board, mapping
    /// the point to [size * row + column]
    pub fn from_linear_index(board_size: u8, index: usize) -> Position {
        Position::new((index / board_size as usize + 1) as u8,
            (index % board_size as usize + 1) as u8)
    }

    /// Maps the position back to its linear index
    pub fn to_linear_index(&self, board_size: u8) -> usize {
        board_size as usize * (self.row as usize - 1) + (self.column as usize - 1)
    }

    /// Checks if the position is a border point
    /// and thus to be ignored in many cases
    pub fn is_border(&self) -> bool {
        self.row == 0 || self.column == 0
    }

    /// Checks if the position is inside the board
    /// and not a border point.
    pub fn is_inside(&self) -> bool {
        !self.is_border()
    }
}
<commit_msg>fixed compilation error due to newer rust version<commit_after>
/// Represents a position on the board.
/// It starts counting from 1, so that 0 can be used
/// to represent the border.
#[derive(Clone, PartialEq, Eq)]
pub struct Position {
    row: u8,
    column: u8
}

impl Position {
    /// Create a new board position with the given row and column
    pub fn new(r: u8, c: u8) -> Position {
        Position { row: r, column: c }
    }

    /// Generate all positions on the board
    /// (excluding the border)
    pub fn generate_positions(board_size: u8) -> Vec<Position> {
        (0usize..(board_size as usize * board_size as usize))
            .map(|index| Position::from_linear_index(board_size, index))
            .collect()
    }

    /// Creates a new position from a linear index on the board, mapping
    /// the point to [size * row + column]
    pub fn from_linear_index(board_size: u8, index: usize) -> Position {
        Position::new((index / board_size as usize + 1) as u8,
            (index % board_size as usize + 1) as u8)
    }

    /// Maps the position back to its linear index
    pub fn to_linear_index(&self, board_size: u8) -> usize {
        board_size as usize * (self.row as usize - 1) + (self.column as usize - 1)
    }

    /// Checks if the position is a border point
    /// and thus to be ignored in many cases
    pub fn is_border(&self) -> bool {
        self.row == 0 || self.column == 0
    }

    /// Checks if the position is inside the board
    /// and not a border point.
    pub fn is_inside(&self) -> bool {
        !self.is_border()
    }
}
<|endoftext|>


<commit_before>use std::io;

pub struct State(imp::State);

impl State {
    /// Captures the current state of all CPUs on the system.
    ///
    /// The `State` returned here isn't too meaningful in terms of
    /// interpretation across platforms, but it can be compared to previous
    /// states to get a meaningful cross-platform number.
    pub fn current() -> io::Result<State> {
        imp::current().map(State)
    }

    /// Returns the percentage of time CPUs were idle from the current state
    /// relative to the previous state, as a percentage from 0.0 to 100.0.
    ///
    /// This function will return, as a percentage, the amount of time that the
    /// entire system was idle between the `previous` state and this own state.
    /// This can be useful to compare two snapshots in time of CPU usage to see
    /// how the CPU usage compares between the two.
    pub fn idle_since(&self, previous: &State) -> f64 {
        imp::pct_idle(&previous.0, &self.0)
    }
}

#[cfg(target_os = "linux")]
mod imp {
    use std::fs::File;
    use std::io::{self, Read};

    pub struct State {
        user: u64,
        nice: u64,
        system: u64,
        idle: u64,
        iowait: u64,
        irq: u64,
        softirq: u64,
        steal: u64,
        guest: u64,
        guest_nice: u64,
    }

    pub fn current() -> io::Result<State> {
        let mut state = String::new();
        File::open("/proc/stat")?.read_to_string(&mut state)?;
        let mut parts = state.lines().next().unwrap().split_whitespace();
        if parts.next() != Some("cpu") {
            return Err(io::Error::new(
                io::ErrorKind::Other,
                "cannot parse /proc/stat",
            ));
        }

        Ok(State {
            user: parts.next().unwrap().parse::<u64>().unwrap(),
            nice: parts.next().unwrap().parse::<u64>().unwrap(),
            system: parts.next().unwrap().parse::<u64>().unwrap(),
            idle: parts.next().unwrap().parse::<u64>().unwrap(),
            iowait: parts.next().unwrap().parse::<u64>().unwrap(),
            irq: parts.next().unwrap().parse::<u64>().unwrap(),
            softirq: parts.next().unwrap().parse::<u64>().unwrap(),
            steal: parts.next().unwrap().parse::<u64>().unwrap(),
            guest: parts.next().unwrap().parse::<u64>().unwrap(),
            guest_nice: parts.next().unwrap().parse::<u64>().unwrap(),
        })
    }

    pub fn pct_idle(prev: &State, next: &State) -> f64 {
        let user = next.user - prev.user;
        let nice = next.nice - prev.nice;
        let system = next.system - prev.system;
        let idle = next.idle - prev.idle;
        let iowait = next.iowait - prev.iowait;
        let irq = next.irq - prev.irq;
        let softirq = next.softirq - prev.softirq;
        let steal = next.steal - prev.steal;
        let guest = next.guest - prev.guest;
        let guest_nice = next.guest_nice - prev.guest_nice;
        let total =
            user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice;

        (idle as f64) / (total as f64) * 100.0
    }
}

#[cfg(target_os = "macos")]
#[allow(bad_style)]
mod imp {
    use std::io;
    use std::ptr;
    use std::slice;

    type host_t = u32;
    type mach_port_t = u32;
    type processor_flavor_t = i32;
    type natural_t = u32;
    type processor_info_array_t = *mut i32;
    type mach_msg_type_number_t = i32;
    type kern_return_t = i32;

    const PROESSOR_CPU_LOAD_INFO: processor_flavor_t = 2;
    const CPU_STATE_USER: usize = 0;
    const CPU_STATE_SYSTEM: usize = 1;
    const CPU_STATE_IDLE: usize = 2;
    const CPU_STATE_NICE: usize = 3;

    extern "C" {
        fn mach_host_self() -> mach_port_t;
        fn host_processor_info(
            host: host_t,
            flavor: processor_flavor_t,
            out_processor_count: *mut natural_t,
            out_processor_info: *mut processor_info_array_t,
            out_processor_infoCnt: *mut mach_msg_type_number_t,
        ) -> kern_return_t;
    }

    pub struct State {
        user: u64,
        system: u64,
        idle: u64,
        nice: u64,
    }

    pub fn current() -> io::Result<State> {
        unsafe {
            let mut num_cpus_u = 0;
            let mut cpu_info = ptr::null_mut();
            let mut cpu_info_cnt = 0;
            let err = host_processor_info(
                mach_host_self(),
                PROESSOR_CPU_LOAD_INFO,
                &mut num_cpus_u,
                &mut cpu_info,
                &mut cpu_info_cnt,
            );
            if err != 0 {
                return Err(io::Error::last_os_error());
            }
            let cpu_info = slice::from_raw_parts(cpu_info, cpu_info_cnt as usize);
            let mut ret = State {
                user: 0,
                system: 0,
                idle: 0,
                nice: 0,
            };
            for chunk in cpu_info.chunks(num_cpus_u as usize) {
                ret.user += chunk[CPU_STATE_USER] as u64;
                ret.system += chunk[CPU_STATE_SYSTEM] as u64;
                ret.idle += chunk[CPU_STATE_IDLE] as u64;
                ret.nice += chunk[CPU_STATE_NICE] as u64;
            }
            Ok(ret)
        }
    }

    pub fn pct_idle(prev: &State, next: &State) -> f64 {
        let user = next.user - prev.user;
        let system = next.system - prev.system;
        let idle = next.idle - prev.idle;
        let nice = next.nice - prev.nice;
        let total = user + system + idle + nice;
        (idle as f64) / (total as f64) * 100.0
    }
}

#[cfg(windows)]
mod imp {
    use std::io;
    use std::mem;
    use winapi::shared::minwindef::*;
    use winapi::um::processthreadsapi::*;

    pub struct State {
        idle: FILETIME,
        kernel: FILETIME,
        user: FILETIME,
    }

    pub fn current() -> io::Result<State> {
        unsafe {
            let mut ret = mem::zeroed::<State>();
            let r = GetSystemTimes(&mut ret.idle, &mut ret.kernel, &mut ret.user);
            if r != 0 {
                Ok(ret)
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }

    pub fn pct_idle(prev: &State, next: &State) -> f64 {
        fn to_u64(a: &FILETIME) -> u64 {
            ((a.dwHighDateTime as u64) << 32) | (a.dwLowDateTime as u64)
        }

        let idle = to_u64(&next.idle) - to_u64(&prev.idle);
        let kernel = to_u64(&next.kernel) - to_u64(&prev.kernel);
        let user = to_u64(&next.user) - to_u64(&prev.user);
        let total = user + kernel;
        (idle as f64) / (total as f64) * 100.0
    }
}

#[cfg(not(any(target_os = "linux", target_os = "macos", windows)))]
mod imp {
    use std::io;

    pub struct State;

    pub fn current() -> io::Result<State> {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "unsupported platform to learn CPU state",
        ))
    }

    pub fn pct_idle(_prev: &State, _next: &State) -> f64 {
        unimplemented!()
    }
}
<commit_msg>Auto merge of #7429 - alexcrichton:fix-osx-cpu, r=ehuss<commit_after>use std::io;

pub struct State(imp::State);

impl State {
    /// Captures the current state of all CPUs on the system.
    ///
    /// The `State` returned here isn't too meaningful in terms of
    /// interpretation across platforms, but it can be compared to previous
    /// states to get a meaningful cross-platform number.
    pub fn current() -> io::Result<State> {
        imp::current().map(State)
    }

    /// Returns the percentage of time CPUs were idle from the current state
    /// relative to the previous state, as a percentage from 0.0 to 100.0.
    ///
    /// This function will return, as a percentage, the amount of time that the
    /// entire system was idle between the `previous` state and this own state.
    /// This can be useful to compare two snapshots in time of CPU usage to see
    /// how the CPU usage compares between the two.
    pub fn idle_since(&self, previous: &State) -> f64 {
        imp::pct_idle(&previous.0, &self.0)
    }
}

#[cfg(target_os = "linux")]
mod imp {
    use std::fs::File;
    use std::io::{self, Read};

    pub struct State {
        user: u64,
        nice: u64,
        system: u64,
        idle: u64,
        iowait: u64,
        irq: u64,
        softirq: u64,
        steal: u64,
        guest: u64,
        guest_nice: u64,
    }

    pub fn current() -> io::Result<State> {
        let mut state = String::new();
        File::open("/proc/stat")?.read_to_string(&mut state)?;
        let mut parts = state.lines().next().unwrap().split_whitespace();
        if parts.next() != Some("cpu") {
            return Err(io::Error::new(
                io::ErrorKind::Other,
                "cannot parse /proc/stat",
            ));
        }

        Ok(State {
            user: parts.next().unwrap().parse::<u64>().unwrap(),
            nice: parts.next().unwrap().parse::<u64>().unwrap(),
            system: parts.next().unwrap().parse::<u64>().unwrap(),
            idle: parts.next().unwrap().parse::<u64>().unwrap(),
            iowait: parts.next().unwrap().parse::<u64>().unwrap(),
            irq: parts.next().unwrap().parse::<u64>().unwrap(),
            softirq: parts.next().unwrap().parse::<u64>().unwrap(),
            steal: parts.next().unwrap().parse::<u64>().unwrap(),
            guest: parts.next().unwrap().parse::<u64>().unwrap(),
            guest_nice: parts.next().unwrap().parse::<u64>().unwrap(),
        })
    }

    pub fn pct_idle(prev: &State, next: &State) -> f64 {
        let user = next.user - prev.user;
        let nice = next.nice - prev.nice;
        let system = next.system - prev.system;
        let idle = next.idle - prev.idle;
        let iowait = next.iowait - prev.iowait;
        let irq = next.irq - prev.irq;
        let softirq = next.softirq - prev.softirq;
        let steal = next.steal - prev.steal;
        let guest = next.guest - prev.guest;
        let guest_nice = next.guest_nice - prev.guest_nice;
        let total =
            user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice;

        (idle as f64) / (total as f64) * 100.0
    }
}

#[cfg(target_os = "macos")]
#[allow(bad_style)]
mod imp {
    use std::io;
    use std::ptr;

    type host_t = u32;
    type mach_port_t = u32;
    type vm_map_t = mach_port_t;
    type vm_offset_t = usize;
    type vm_size_t = usize;
    type vm_address_t = vm_offset_t;
    type processor_flavor_t = i32;
    type natural_t = u32;
    type processor_info_array_t = *mut i32;
    type mach_msg_type_number_t = i32;
    type kern_return_t = i32;

    const PROESSOR_CPU_LOAD_INFO: processor_flavor_t = 2;
    const CPU_STATE_USER: usize = 0;
    const CPU_STATE_SYSTEM: usize = 1;
    const CPU_STATE_IDLE: usize = 2;
    const CPU_STATE_NICE: usize = 3;
    const CPU_STATE_MAX: usize = 4;

    extern "C" {
        static mut mach_task_self_: mach_port_t;

        fn mach_host_self() -> mach_port_t;
        fn host_processor_info(
            host: host_t,
            flavor: processor_flavor_t,
            out_processor_count: *mut natural_t,
            out_processor_info: *mut processor_info_array_t,
            out_processor_infoCnt: *mut mach_msg_type_number_t,
        ) -> kern_return_t;
        fn vm_deallocate(
            target_task: vm_map_t,
            address: vm_address_t,
            size: vm_size_t,
        ) -> kern_return_t;
    }

    pub struct State {
        user: u64,
        system: u64,
        idle: u64,
        nice: u64,
    }

    #[repr(C)]
    struct processor_cpu_load_info_data_t {
        cpu_ticks: [u32; CPU_STATE_MAX],
    }

    pub fn current() -> io::Result<State> {
        // There's scant little documentation on `host_processor_info`
        // throughout the internet, so this is just modeled after what everyone
        // else is doing. For now this is modeled largely after libuv.

        unsafe {
            let mut num_cpus_u = 0;
            let mut cpu_info = ptr::null_mut();
            let mut msg_type = 0;
            let err = host_processor_info(
                mach_host_self(),
                PROESSOR_CPU_LOAD_INFO,
                &mut num_cpus_u,
                &mut cpu_info,
                &mut msg_type,
            );
            if err != 0 {
                return Err(io::Error::last_os_error());
            }
            let mut ret = State {
                user: 0,
                system: 0,
                idle: 0,
                nice: 0,
            };
            let mut current = cpu_info as *const processor_cpu_load_info_data_t;
            for _ in 0..num_cpus_u {
                ret.user += (*current).cpu_ticks[CPU_STATE_USER] as u64;
                ret.system += (*current).cpu_ticks[CPU_STATE_SYSTEM] as u64;
                ret.idle += (*current).cpu_ticks[CPU_STATE_IDLE] as u64;
                ret.nice += (*current).cpu_ticks[CPU_STATE_NICE] as u64;
                current = current.offset(1);
            }
            vm_deallocate(mach_task_self_, cpu_info as vm_address_t, msg_type as usize);
            Ok(ret)
        }
    }

    pub fn pct_idle(prev: &State, next: &State) -> f64 {
        let user = next.user - prev.user;
        let system = next.system - prev.system;
        let idle = next.idle - prev.idle;
        let nice = next.nice - prev.nice;
        let total = user + system + idle + nice;
        (idle as f64) / (total as f64) * 100.0
    }
}

#[cfg(windows)]
mod imp {
    use std::io;
    use std::mem;
    use winapi::shared::minwindef::*;
    use winapi::um::processthreadsapi::*;

    pub struct State {
        idle: FILETIME,
        kernel: FILETIME,
        user: FILETIME,
    }

    pub fn current() -> io::Result<State> {
        unsafe {
            let mut ret = mem::zeroed::<State>();
            let r = GetSystemTimes(&mut ret.idle, &mut ret.kernel, &mut ret.user);
            if r != 0 {
                Ok(ret)
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }

    pub fn pct_idle(prev: &State, next: &State) -> f64 {
        fn to_u64(a: &FILETIME) -> u64 {
            ((a.dwHighDateTime as u64) << 32) | (a.dwLowDateTime as u64)
        }

        let idle = to_u64(&next.idle) - to_u64(&prev.idle);
        let kernel = to_u64(&next.kernel) - to_u64(&prev.kernel);
        let user = to_u64(&next.user) - to_u64(&prev.user);
        let total = user + kernel;
        (idle as f64) / (total as f64) * 100.0
    }
}

#[cfg(not(any(target_os = "linux", target_os = "macos", windows)))]
mod imp {
    use std::io;

    pub struct State;

    pub fn current() -> io::Result<State> {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "unsupported platform to learn CPU state",
        ))
    }

    pub fn pct_idle(_prev: &State, _next: &State) -> f64 {
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>use color::Color;
use tile::Tile;
use ::Axis;

pub const ALIGN_HORIZONTAL: usize = 0;
pub const ALIGN_DIAGONAL_UP: usize  = 1;
pub const ALIGN_VERTICAL: usize  = 2;
pub const ALIGN_DIAGONAL_DOWN: usize  = 3;

pub fn horizontal_alignement(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> usize {
    let tile = grid[pos.x][pos.y].unwrap();
    let mut count = 0;
    for y in (pos.y...0).rev() {
        match grid[pos.x][y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
    }
    for y in pos.y + 1..::GRID_LEN {
        match grid[pos.x][y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
    }
    count
}

pub fn diagonal_up_alignement(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> usize {
    let tile = grid[pos.x][pos.y].unwrap();
    let mut count = 0;
    let Axis { mut x, mut y } = pos;
    while x < ::GRID_LEN && y < ::GRID_LEN { // x will underflow to usize::max()
        match grid[x][y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
        x += 1;
        y = y.wrapping_sub(1);
    }
    let Axis { mut x, mut y } = pos;
    x = x.wrapping_sub(1);
    y += 1;
    while x < ::GRID_LEN && y < ::GRID_LEN {
        match grid[x][y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
        x = x.wrapping_sub(1);
        y += 1;
    }
    count
}

pub fn vertical_alignement(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> usize {
    let tile = grid[pos.x][pos.y].unwrap();
    let mut count = 0;
    for x in (pos.x...0).rev() {
        match grid[x][pos.y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
    }
    for x in pos.x + 1..::GRID_LEN {
        match grid[x][pos.y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
    }
    count
}

pub fn diagonal_down_alignement(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> usize {
    let tile = grid[pos.x][pos.y].unwrap();
    let mut count = 0;
    let Axis { mut x, mut y } = pos;
    while x < ::GRID_LEN && y < ::GRID_LEN { // x and y will overflow to usize::max()
        match grid[x][y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
        x = x.wrapping_sub(1);
        y = y.wrapping_sub(1);
    }
    let Axis { mut x, mut y } = pos;
    x += 1;
    y += 1;
    while x < ::GRID_LEN && y < ::GRID_LEN {
        match grid[x][y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
        x += 1;
        y += 1;
    }
    count
}

/// returns a list of alignements with the tile at `pos` position in Clockwise
/// (e.g. top_to_bot, top_right_to_bot_left, right_to_left, bot_right_to_top_left)
/// a None value means no alignement (e.g. less than 2 stones)
pub fn list_alignements(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> [Option<usize>; 4] {
    let mut alignements = [None; 4];
    alignements[ALIGN_HORIZONTAL] = match horizontal_alignement(grid, pos) {
        0 => unreachable!("horizontal_alignement cannot count zero tiles!"),
        1 => None,
        x => Some(x),
    };
    alignements[ALIGN_DIAGONAL_UP] = match diagonal_up_alignement(grid, pos) {
        0 => unreachable!("diagonal_up_alignement cannot count zero tiles!"),
        1 => None,
        x => Some(x),
    };
    alignements[ALIGN_VERTICAL] = match vertical_alignement(grid, pos) {
        0 => unreachable!("vertical_alignement cannot count zero tiles!"),
        1 => None,
        x => Some(x),
    };
    alignements[ALIGN_DIAGONAL_DOWN] = match diagonal_down_alignement(grid, pos) {
        0 => unreachable!("diagonal_down_alignement cannot count zero tiles!"),
        1 => None,
        x => Some(x),
    };
    alignements
}

#[cfg(test)]
mod tests {

    use test::Bencher;
    use functions::alignements::*;
    use color::Color;

    // #[bench]
    // fn diagonal_up_top_bounds(bencher: &mut Bencher) {
    //     let b = Some(Color::Black);
    //     let n = None;

    //     let grid = [[n, n, n, n, b, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, b, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, b, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, b, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [b, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n]];

    //     bencher.iter(||
    //         assert_eq!(check_diagonal_up_alignement(&grid, Color::Black), true)
    //     );
    // }
}
<commit_msg>alignements: Fix loop ranges for horizontal and vertical alignements<commit_after>use color::Color;
use tile::Tile;
use ::Axis;

pub const ALIGN_HORIZONTAL: usize = 0;
pub const ALIGN_DIAGONAL_UP: usize  = 1;
pub const ALIGN_VERTICAL: usize  = 2;
pub const ALIGN_DIAGONAL_DOWN: usize  = 3;

pub fn horizontal_alignement(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> usize {
    let tile = grid[pos.x][pos.y].unwrap();
    let mut count = 0;
    for y in (0...pos.y).rev() {
        match grid[pos.x][y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
    }
    for y in pos.y + 1..::GRID_LEN {
        match grid[pos.x][y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
    }
    count
}

pub fn diagonal_up_alignement(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> usize {
    let tile = grid[pos.x][pos.y].unwrap();
    let mut count = 0;
    let Axis { mut x, mut y } = pos;
    while x < ::GRID_LEN && y < ::GRID_LEN { // x will underflow to usize::max()
        match grid[x][y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
        x += 1;
        y = y.wrapping_sub(1);
    }
    let Axis { mut x, mut y } = pos;
    x = x.wrapping_sub(1);
    y += 1;
    while x < ::GRID_LEN && y < ::GRID_LEN {
        match grid[x][y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
        x = x.wrapping_sub(1);
        y += 1;
    }
    count
}

pub fn vertical_alignement(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> usize {
    let tile = grid[pos.x][pos.y].unwrap();
    let mut count = 0;
    for x in (0...pos.x).rev() {
        match grid[x][pos.y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
    }
    for x in pos.x + 1..::GRID_LEN {
        match grid[x][pos.y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
    }
    count
}

pub fn diagonal_down_alignement(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> usize {
    let tile = grid[pos.x][pos.y].unwrap();
    let mut count = 0;
    let Axis { mut x, mut y } = pos;
    while x < ::GRID_LEN && y < ::GRID_LEN { // x and y will overflow to usize::max()
        match grid[x][y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
        x = x.wrapping_sub(1);
        y = y.wrapping_sub(1);
    }
    let Axis { mut x, mut y } = pos;
    x += 1;
    y += 1;
    while x < ::GRID_LEN && y < ::GRID_LEN {
        match grid[x][y] {
            Some(c) if c == tile => count += 1,
            _ => break,
        }
        x += 1;
        y += 1;
    }
    count
}

/// returns a list of alignements with the tile at `pos` position in Clockwise
/// (e.g. top_to_bot, top_right_to_bot_left, right_to_left, bot_right_to_top_left)
/// a None value means no alignement (e.g. less than 2 stones)
pub fn list_alignements(grid: &[[Tile; ::GRID_LEN]; ::GRID_LEN], pos: Axis) -> [Option<usize>; 4] {
    let mut alignements = [None; 4];
    alignements[ALIGN_HORIZONTAL] = match horizontal_alignement(grid, pos) {
        0 => unreachable!("horizontal_alignement cannot count zero tiles!"),
        1 => None,
        x => Some(x),
    };
    alignements[ALIGN_DIAGONAL_UP] = match diagonal_up_alignement(grid, pos) {
        0 => unreachable!("diagonal_up_alignement cannot count zero tiles!"),
        1 => None,
        x => Some(x),
    };
    alignements[ALIGN_VERTICAL] = match vertical_alignement(grid, pos) {
        0 => unreachable!("vertical_alignement cannot count zero tiles!"),
        1 => None,
        x => Some(x),
    };
    alignements[ALIGN_DIAGONAL_DOWN] = match diagonal_down_alignement(grid, pos) {
        0 => unreachable!("diagonal_down_alignement cannot count zero tiles!"),
        1 => None,
        x => Some(x),
    };
    alignements
}

#[cfg(test)]
mod tests {

    use test::Bencher;
    use functions::alignements::*;
    use color::Color;

    // #[bench]
    // fn diagonal_up_top_bounds(bencher: &mut Bencher) {
    //     let b = Some(Color::Black);
    //     let n = None;

    //     let grid = [[n, n, n, n, b, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, b, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, b, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, b, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [b, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n],
    //                 [n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n]];

    //     bencher.iter(||
    //         assert_eq!(check_diagonal_up_alignement(&grid, Color::Black), true)
    //     );
    // }
}
<|endoftext|>


<commit_before>use winapi::um::winuser::{WS_OVERLAPPEDWINDOW, WS_CLIPCHILDREN, WS_VISIBLE, WS_DISABLED, WS_MAXIMIZE, WS_MINIMIZE, WS_CAPTION,
WS_MINIMIZEBOX, WS_MAXIMIZEBOX, WS_SYSMENU, WS_THICKFRAME, WS_POPUP, WS_EX_TOPMOST, WS_EX_ACCEPTFILES};

use crate::win32::window_helper as wh;
use crate::win32::base_helper::check_hwnd;
use crate::{NwgError, Icon};
use super::{ControlBase, ControlHandle};

const NOT_BOUND: &'static str = "Window is not yet bound to a winapi object";
const BAD_HANDLE: &'static str = "INTERNAL ERROR: Window handle is not HWND!";

bitflags! {

    /**
        The window flags.

        Example: `WindowFlags::MAIN_WINDOW | WindowFlags::VISIBLE`

        Window flags:
        * MAIN_WINDOW: Combine all the top level system window decoration: A title, a system menu, a resizable frame, and the close, minimize, maximize buttons
        * WINDOW:  A window with a title, a system menu, a close button, and a non resizable border.
        * MINIMIZE_BOX: Includes a minimize button
        * MAXIMIZE_BOX: Includes a maximize button
        * SYS_MENU: Includes a system menu when the user right click the window header
        * MAXIMIZED: Create the window as maximized
        * MINIMIZED: Create the window as minimized
        * RESIZABLE: Add a resizable border
        * VISIBLE: Show the window right away
    */
    pub struct WindowFlags: u32 {
        const MAIN_WINDOW = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_THICKFRAME | WS_MAXIMIZEBOX;
        const WINDOW = WS_CAPTION | WS_SYSMENU;
        const MINIMIZE_BOX = WS_MINIMIZEBOX;
        const MAXIMIZE_BOX = WS_MAXIMIZEBOX;
        const SYS_MENU = WS_SYSMENU;
        const VISIBLE = WS_VISIBLE;
        const DISABLED = WS_DISABLED;
        const MAXIMIZED = WS_MAXIMIZE;
        const MINIMIZED = WS_MINIMIZE;
        const RESIZABLE = WS_THICKFRAME | WS_MAXIMIZEBOX;
        const POPUP = WS_POPUP;
    }
}

/**
    A basic top level window. At least one top level window is required to make a NWG application.

    Windows can be heavily customized using the window flags. If your application don't need a visible window
    (ex: a system tray app), use `MessageWindow` instead.

    **Builder parameters:**
      * `flags`:       The window flags. See `WindowFlags`
      * `ex_flags`:    A combination of win32 window extended flags. Unlike `flags`, ex_flags must be used straight from winapi
      * `title`:       The text in the window title bar
      * `size`:        The default size of the window
      * `position`:    The default position of the window in the desktop
      * `icon`:        The window icon
      * `accept_file`: If the window should accept files by drag & drop
      * `maximized`:   If the window should be maximized at creation
      * `minimized`:   If the window should be minimized at creation
      * `center`:      Center the window in the current monitor based on its size. If `true`, this overrides `position`
      * `topmost`:     If the window should always be on top of other system window
      * `parent`:      Logical parent of the window, unlike children controls, this is NOT required.

    **Control events:**
      * `OnInit`: The window was created
      * `MousePress(_)`: Generic mouse press events on the button
      * `OnMouseMove`: Generic mouse mouse event
      * `OnMouseWheel`: Generic mouse wheel event
      * `OnPaint`: Generic on paint event
      * `OnKeyPress`: Generic key press
      * `OnKeyRelease`: Generic ket release
      * `OnResize`: When the window is resized
      * `OnResizeBegin`: Just before the window begins being resized by the user
      * `OnResizeEnd`: Just after the user stops resizing the window
      * `OnWindowMaximize`: When the window is maximized
      * `OnWindowMinimize`: When the window is minimized
      * `OnMove`: When the window is moved by the user
      * `OnFileDrop`: When a file is dropped in the window (only raised if accept_file is set)
      * `OnMinMaxInfo`: When the size or position of the window is about to change and the size of the windows must be restricted

*/
#[derive(Default, PartialEq, Eq)]
pub struct Window {
    pub handle: ControlHandle
}

impl Window {

    pub fn builder<'a>() -> WindowBuilder<'a> {
        WindowBuilder {
            title: "New Window",
            size: (500, 500),
            position: (300, 300),
            accept_files: false,
            topmost: false,
            center: false,
            maximized: false,
            minimized: false,
            flags: None,
            ex_flags: 0,
            icon: None,
            parent: None
        }
    }

    /// Maximize the window
    pub fn maximize(&self) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        wh::maximize_window(handle);
    }

    /// Minimize the window
    pub fn minimize(&self) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        wh::minimize_window(handle);
    }

    /// Restore a minimized/maximized window
    pub fn restore(&self) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        wh::restore_window(handle);
    }

    /// Force the window to refraw iteself and all its children
    pub fn invalidate(&self) {
        use winapi::um::winuser::InvalidateRect;

        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { InvalidateRect(handle, ::std::ptr::null(), 1); }
    }

    /// Close the window as if the user clicked the X button.
    pub fn close(&self) {
        use winapi::um::winuser::WM_CLOSE;

        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        wh::post_message(handle, WM_CLOSE, 0, 0);
    }

    /// Return the icon of the window
    pub fn icon(&self) -> Option<Icon> {
        use winapi::um::winuser::WM_GETICON;
        use winapi::um::winnt::HANDLE;

        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        let handle = wh::send_message(handle, WM_GETICON, 0, 0);
        if handle == 0 {
            None
        } else {
            Some(Icon { handle: handle as HANDLE, owned: false })
        }
    }

    /// Set the icon in the window
    /// - icon: The new icon. If None, the icon is removed
    pub fn set_icon(&self, icon: Option<&Icon>) {
        use winapi::um::winuser::WM_SETICON;
        use std::{mem, ptr};

        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);

        let image_handle = icon.map(|i| i.handle).unwrap_or(ptr::null_mut());
        unsafe {
            wh::send_message(handle, WM_SETICON, 0, mem::transmute(image_handle));
        }
    }

    /// Return true if the control currently has the keyboard focus
    pub fn focus(&self) -> bool {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::get_focus(handle) }
    }

    /// Set the keyboard focus on the button
    pub fn set_focus(&self) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::set_focus(handle); }
    }

    /// Return true if the control user can interact with the control, return false otherwise
    pub fn enabled(&self) -> bool {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::get_window_enabled(handle) }
    }

    /// Enable or disable the control
    pub fn set_enabled(&self, v: bool) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::set_window_enabled(handle, v) }
    }

    /// Return true if the control is visible to the user. Will return true even if the
    /// control is outside of the parent client view (ex: at the position (10000, 10000))
    pub fn visible(&self) -> bool {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::get_window_visibility(handle) }
    }

    /// Show or hide the control to the user
    pub fn set_visible(&self, v: bool) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::set_window_visibility(handle, v) }
    }

    /// Return the size of the button in the parent window
    pub fn size(&self) -> (u32, u32) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::get_window_size(handle) }
    }

    /// Set the size of the button in the parent window
    pub fn set_size(&self, x: u32, y: u32) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::set_window_size(handle, x, y, true) }
    }

    /// Return the position of the button in the parent window
    pub fn position(&self) -> (i32, i32) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::get_window_position(handle) }
    }

    /// Set the position of the button in the parent window
    pub fn set_position(&self, x: i32, y: i32) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::set_window_position(handle, x, y) }
    }

    /// Return window title
    pub fn text(&self) -> String {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::get_window_text(handle) }
    }

    /// Set the window title
    pub fn set_text<'a>(&self, v: &'a str) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::set_window_text(handle, v) }
    }

    /// Winapi class name used during control creation
    pub fn class_name(&self) -> &'static str {
        "NativeWindowsGuiWindow"
    }

    // Winapi base flags used during window creation
    pub fn flags(&self) -> u32 {
        WS_OVERLAPPEDWINDOW | WS_VISIBLE
    }

    /// Winapi flags required by the control
    pub fn forced_flags(&self) -> u32 {
        WS_CLIPCHILDREN
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        self.handle.destroy();
    }
}

#[cfg(feature = "raw-win-handle")]
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle, windows::WindowsHandle};

#[cfg(feature = "raw-win-handle")]
unsafe impl HasRawWindowHandle for Window {
    fn raw_window_handle(&self) -> RawWindowHandle {
        use winapi::um::winuser::GWL_HINSTANCE;
        match self.handle {
            ControlHandle::Hwnd(hwnd) => {
                let hinstance = wh::get_window_long(hwnd, GWL_HINSTANCE);

                RawWindowHandle::Windows(WindowsHandle {
                    hwnd: hwnd as _,
                    hinstance: hinstance as _,
                    ..WindowsHandle::empty()
                })
            }
            // Not a valid window handle, so return an empty handle
            _ => RawWindowHandle::Windows(WindowsHandle::empty())
        }
    }
}

pub struct WindowBuilder<'a> {
    title: &'a str,
    size: (i32, i32),
    position: (i32, i32),
    accept_files: bool,
    center: bool,
    topmost: bool,
    maximized: bool,
    minimized: bool,
    flags: Option<WindowFlags>,
    ex_flags: u32,
    icon: Option<&'a Icon>,
    parent: Option<ControlHandle>
}

impl<'a> WindowBuilder<'a> {

    pub fn flags(mut self, flags: WindowFlags) -> WindowBuilder<'a> {
        self.flags = Some(flags);
        self
    }

    pub fn ex_flags(mut self, flags: u32) -> WindowBuilder<'a> {
        self.ex_flags = flags;
        self
    }

    pub fn title(mut self, text: &'a str) -> WindowBuilder<'a> {
        self.title = text;
        self
    }

    pub fn size(mut self, size: (i32, i32)) -> WindowBuilder<'a> {
        self.size = size;
        self
    }

    pub fn position(mut self, pos: (i32, i32)) -> WindowBuilder<'a> {
        self.position = pos;
        self
    }

    pub fn icon(mut self, ico: Option<&'a Icon>) -> WindowBuilder<'a> {
        self.icon = ico;
        self
    }

    pub fn accept_files(mut self, accept_files: bool) -> WindowBuilder<'a> {
        self.accept_files = accept_files;
        self
    }

    pub fn topmost(mut self, topmost: bool) -> WindowBuilder<'a> {
        self.topmost = topmost;
        self
    }

    pub fn center(mut self, center: bool) -> WindowBuilder<'a> {
        self.center = center;
        self
    }

    pub fn maximized(mut self, maximized: bool) -> WindowBuilder<'a> {
        self.maximized = maximized;
        self
    }

    pub fn minimized(mut self, minimized: bool) -> WindowBuilder<'a> {
        self.minimized = minimized;
        self
    }

    pub fn parent<C: Into<ControlHandle>>(mut self, p: Option<C>) -> WindowBuilder<'a> {
        self.parent = p.map(|p2| p2.into());
        self
    }

    pub fn build(self, out: &mut Window) -> Result<(), NwgError> {
        let flags = self.flags.map(|f| f.bits()).unwrap_or(out.flags());

        let mut ex_flags = self.ex_flags;
        if self.topmost { ex_flags |= WS_EX_TOPMOST; }
        if self.accept_files { ex_flags |= WS_EX_ACCEPTFILES; }

        *out = Default::default();

        out.handle = ControlBase::build_hwnd()
            .class_name(out.class_name())
            .forced_flags(out.forced_flags())
            .ex_flags(ex_flags)
            .flags(flags)
            .size(self.size)
            .position(self.position)
            .text(self.title)
            .parent(self.parent)
            .build()?;

        if self.icon.is_some() {
            out.set_icon(self.icon);
        }

        if self.center {
            let [left, top, right, bottom] = crate::Monitor::monitor_rect_from_window(out as &Window);
            let [m_width, m_height] = [right-left, bottom-top];
            let (width, height) = self.size;

            let x = left + ((m_width-width)/2);
            let y = top + ((m_height-height)/2);

            out.set_position(x, y);
        } else if self.maximized {
            out.maximize();
        } else if self.minimized {
            out.minimize();
        }

        Ok(())
    }

}
<commit_msg>fix window center with hi dpi<commit_after>use winapi::um::winuser::{WS_OVERLAPPEDWINDOW, WS_CLIPCHILDREN, WS_VISIBLE, WS_DISABLED, WS_MAXIMIZE, WS_MINIMIZE, WS_CAPTION,
WS_MINIMIZEBOX, WS_MAXIMIZEBOX, WS_SYSMENU, WS_THICKFRAME, WS_POPUP, WS_EX_TOPMOST, WS_EX_ACCEPTFILES};

use crate::win32::window_helper as wh;
use crate::win32::base_helper::check_hwnd;
use crate::{NwgError, Icon};
use super::{ControlBase, ControlHandle};

const NOT_BOUND: &'static str = "Window is not yet bound to a winapi object";
const BAD_HANDLE: &'static str = "INTERNAL ERROR: Window handle is not HWND!";

bitflags! {

    /**
        The window flags.

        Example: `WindowFlags::MAIN_WINDOW | WindowFlags::VISIBLE`

        Window flags:
        * MAIN_WINDOW: Combine all the top level system window decoration: A title, a system menu, a resizable frame, and the close, minimize, maximize buttons
        * WINDOW:  A window with a title, a system menu, a close button, and a non resizable border.
        * MINIMIZE_BOX: Includes a minimize button
        * MAXIMIZE_BOX: Includes a maximize button
        * SYS_MENU: Includes a system menu when the user right click the window header
        * MAXIMIZED: Create the window as maximized
        * MINIMIZED: Create the window as minimized
        * RESIZABLE: Add a resizable border
        * VISIBLE: Show the window right away
    */
    pub struct WindowFlags: u32 {
        const MAIN_WINDOW = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_THICKFRAME | WS_MAXIMIZEBOX;
        const WINDOW = WS_CAPTION | WS_SYSMENU;
        const MINIMIZE_BOX = WS_MINIMIZEBOX;
        const MAXIMIZE_BOX = WS_MAXIMIZEBOX;
        const SYS_MENU = WS_SYSMENU;
        const VISIBLE = WS_VISIBLE;
        const DISABLED = WS_DISABLED;
        const MAXIMIZED = WS_MAXIMIZE;
        const MINIMIZED = WS_MINIMIZE;
        const RESIZABLE = WS_THICKFRAME | WS_MAXIMIZEBOX;
        const POPUP = WS_POPUP;
    }
}

/**
    A basic top level window. At least one top level window is required to make a NWG application.

    Windows can be heavily customized using the window flags. If your application don't need a visible window
    (ex: a system tray app), use `MessageWindow` instead.

    **Builder parameters:**
      * `flags`:       The window flags. See `WindowFlags`
      * `ex_flags`:    A combination of win32 window extended flags. Unlike `flags`, ex_flags must be used straight from winapi
      * `title`:       The text in the window title bar
      * `size`:        The default size of the window
      * `position`:    The default position of the window in the desktop
      * `icon`:        The window icon
      * `accept_file`: If the window should accept files by drag & drop
      * `maximized`:   If the window should be maximized at creation
      * `minimized`:   If the window should be minimized at creation
      * `center`:      Center the window in the current monitor based on its size. If `true`, this overrides `position`
      * `topmost`:     If the window should always be on top of other system window
      * `parent`:      Logical parent of the window, unlike children controls, this is NOT required.

    **Control events:**
      * `OnInit`: The window was created
      * `MousePress(_)`: Generic mouse press events on the button
      * `OnMouseMove`: Generic mouse mouse event
      * `OnMouseWheel`: Generic mouse wheel event
      * `OnPaint`: Generic on paint event
      * `OnKeyPress`: Generic key press
      * `OnKeyRelease`: Generic ket release
      * `OnResize`: When the window is resized
      * `OnResizeBegin`: Just before the window begins being resized by the user
      * `OnResizeEnd`: Just after the user stops resizing the window
      * `OnWindowMaximize`: When the window is maximized
      * `OnWindowMinimize`: When the window is minimized
      * `OnMove`: When the window is moved by the user
      * `OnFileDrop`: When a file is dropped in the window (only raised if accept_file is set)
      * `OnMinMaxInfo`: When the size or position of the window is about to change and the size of the windows must be restricted

*/
#[derive(Default, PartialEq, Eq)]
pub struct Window {
    pub handle: ControlHandle
}

impl Window {

    pub fn builder<'a>() -> WindowBuilder<'a> {
        WindowBuilder {
            title: "New Window",
            size: (500, 500),
            position: (300, 300),
            accept_files: false,
            topmost: false,
            center: false,
            maximized: false,
            minimized: false,
            flags: None,
            ex_flags: 0,
            icon: None,
            parent: None
        }
    }

    /// Maximize the window
    pub fn maximize(&self) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        wh::maximize_window(handle);
    }

    /// Minimize the window
    pub fn minimize(&self) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        wh::minimize_window(handle);
    }

    /// Restore a minimized/maximized window
    pub fn restore(&self) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        wh::restore_window(handle);
    }

    /// Force the window to refraw iteself and all its children
    pub fn invalidate(&self) {
        use winapi::um::winuser::InvalidateRect;

        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { InvalidateRect(handle, ::std::ptr::null(), 1); }
    }

    /// Close the window as if the user clicked the X button.
    pub fn close(&self) {
        use winapi::um::winuser::WM_CLOSE;

        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        wh::post_message(handle, WM_CLOSE, 0, 0);
    }

    /// Return the icon of the window
    pub fn icon(&self) -> Option<Icon> {
        use winapi::um::winuser::WM_GETICON;
        use winapi::um::winnt::HANDLE;

        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        let handle = wh::send_message(handle, WM_GETICON, 0, 0);
        if handle == 0 {
            None
        } else {
            Some(Icon { handle: handle as HANDLE, owned: false })
        }
    }

    /// Set the icon in the window
    /// - icon: The new icon. If None, the icon is removed
    pub fn set_icon(&self, icon: Option<&Icon>) {
        use winapi::um::winuser::WM_SETICON;
        use std::{mem, ptr};

        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);

        let image_handle = icon.map(|i| i.handle).unwrap_or(ptr::null_mut());
        unsafe {
            wh::send_message(handle, WM_SETICON, 0, mem::transmute(image_handle));
        }
    }

    /// Return true if the control currently has the keyboard focus
    pub fn focus(&self) -> bool {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::get_focus(handle) }
    }

    /// Set the keyboard focus on the button
    pub fn set_focus(&self) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::set_focus(handle); }
    }

    /// Return true if the control user can interact with the control, return false otherwise
    pub fn enabled(&self) -> bool {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::get_window_enabled(handle) }
    }

    /// Enable or disable the control
    pub fn set_enabled(&self, v: bool) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::set_window_enabled(handle, v) }
    }

    /// Return true if the control is visible to the user. Will return true even if the
    /// control is outside of the parent client view (ex: at the position (10000, 10000))
    pub fn visible(&self) -> bool {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::get_window_visibility(handle) }
    }

    /// Show or hide the control to the user
    pub fn set_visible(&self, v: bool) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::set_window_visibility(handle, v) }
    }

    /// Return the size of the button in the parent window
    pub fn size(&self) -> (u32, u32) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::get_window_size(handle) }
    }

    /// Set the size of the button in the parent window
    pub fn set_size(&self, x: u32, y: u32) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::set_window_size(handle, x, y, true) }
    }

    /// Return the position of the button in the parent window
    pub fn position(&self) -> (i32, i32) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::get_window_position(handle) }
    }

    /// Set the position of the button in the parent window
    pub fn set_position(&self, x: i32, y: i32) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::set_window_position(handle, x, y) }
    }

    /// Return window title
    pub fn text(&self) -> String {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::get_window_text(handle) }
    }

    /// Set the window title
    pub fn set_text<'a>(&self, v: &'a str) {
        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
        unsafe { wh::set_window_text(handle, v) }
    }

    /// Winapi class name used during control creation
    pub fn class_name(&self) -> &'static str {
        "NativeWindowsGuiWindow"
    }

    // Winapi base flags used during window creation
    pub fn flags(&self) -> u32 {
        WS_OVERLAPPEDWINDOW | WS_VISIBLE
    }

    /// Winapi flags required by the control
    pub fn forced_flags(&self) -> u32 {
        WS_CLIPCHILDREN
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        self.handle.destroy();
    }
}

#[cfg(feature = "raw-win-handle")]
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle, windows::WindowsHandle};

#[cfg(feature = "raw-win-handle")]
unsafe impl HasRawWindowHandle for Window {
    fn raw_window_handle(&self) -> RawWindowHandle {
        use winapi::um::winuser::GWL_HINSTANCE;
        match self.handle {
            ControlHandle::Hwnd(hwnd) => {
                let hinstance = wh::get_window_long(hwnd, GWL_HINSTANCE);

                RawWindowHandle::Windows(WindowsHandle {
                    hwnd: hwnd as _,
                    hinstance: hinstance as _,
                    ..WindowsHandle::empty()
                })
            }
            // Not a valid window handle, so return an empty handle
            _ => RawWindowHandle::Windows(WindowsHandle::empty())
        }
    }
}

pub struct WindowBuilder<'a> {
    title: &'a str,
    size: (i32, i32),
    position: (i32, i32),
    accept_files: bool,
    center: bool,
    topmost: bool,
    maximized: bool,
    minimized: bool,
    flags: Option<WindowFlags>,
    ex_flags: u32,
    icon: Option<&'a Icon>,
    parent: Option<ControlHandle>
}

impl<'a> WindowBuilder<'a> {

    pub fn flags(mut self, flags: WindowFlags) -> WindowBuilder<'a> {
        self.flags = Some(flags);
        self
    }

    pub fn ex_flags(mut self, flags: u32) -> WindowBuilder<'a> {
        self.ex_flags = flags;
        self
    }

    pub fn title(mut self, text: &'a str) -> WindowBuilder<'a> {
        self.title = text;
        self
    }

    pub fn size(mut self, size: (i32, i32)) -> WindowBuilder<'a> {
        self.size = size;
        self
    }

    pub fn position(mut self, pos: (i32, i32)) -> WindowBuilder<'a> {
        self.position = pos;
        self
    }

    pub fn icon(mut self, ico: Option<&'a Icon>) -> WindowBuilder<'a> {
        self.icon = ico;
        self
    }

    pub fn accept_files(mut self, accept_files: bool) -> WindowBuilder<'a> {
        self.accept_files = accept_files;
        self
    }

    pub fn topmost(mut self, topmost: bool) -> WindowBuilder<'a> {
        self.topmost = topmost;
        self
    }

    pub fn center(mut self, center: bool) -> WindowBuilder<'a> {
        self.center = center;
        self
    }

    pub fn maximized(mut self, maximized: bool) -> WindowBuilder<'a> {
        self.maximized = maximized;
        self
    }

    pub fn minimized(mut self, minimized: bool) -> WindowBuilder<'a> {
        self.minimized = minimized;
        self
    }

    pub fn parent<C: Into<ControlHandle>>(mut self, p: Option<C>) -> WindowBuilder<'a> {
        self.parent = p.map(|p2| p2.into());
        self
    }

    pub fn build(self, out: &mut Window) -> Result<(), NwgError> {
        use crate::win32::high_dpi::physical_to_logical;

        let flags = self.flags.map(|f| f.bits()).unwrap_or(out.flags());

        let mut ex_flags = self.ex_flags;
        if self.topmost { ex_flags |= WS_EX_TOPMOST; }
        if self.accept_files { ex_flags |= WS_EX_ACCEPTFILES; }

        *out = Default::default();

        out.handle = ControlBase::build_hwnd()
            .class_name(out.class_name())
            .forced_flags(out.forced_flags())
            .ex_flags(ex_flags)
            .flags(flags)
            .size(self.size)
            .position(self.position)
            .text(self.title)
            .parent(self.parent)
            .build()?;

        if self.icon.is_some() {
            out.set_icon(self.icon);
        }

        if self.center {
            let [left, top, right, bottom] = crate::Monitor::monitor_rect_from_window(out as &Window);
            let (m_width, m_height) = unsafe { physical_to_logical(right-left, bottom-top) };
            let (width, height) = self.size;

            let x = left + ((m_width-width)/2);
            let y = top + ((m_height-height)/2);

            out.set_position(x, y);
        } else if self.maximized {
            out.maximize();
        } else if self.minimized {
            out.minimize();
        }

        Ok(())
    }

}
<|endoftext|>