<commit_before>// NO-RUSTC-WRAPPER
#![deny(warnings, rust_2018_idioms, unused_lifetimes)]

use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::time::{SystemTime, UNIX_EPOCH};
use std::{env, fs};
use std::thread;

/// A helper macro to `unwrap` a result except also print out details like:
///
/// * The file/line of the panic
/// * The expression that failed
/// * The error itself
///
/// This is currently used judiciously throughout the build system rather than
/// using a `Result` with `try!`, but this may change one day...
#[macro_export]
macro_rules! t {
    ($e:expr) => {
        match $e {
            Ok(e) => e,
            Err(e) => panic!("{} failed with {}", stringify!($e), e),
        }
    };
}

// Because Cargo adds the compiler's dylib path to our library search path, llvm-config may
// break: the dylib path for the compiler, as of this writing, contains a copy of the LLVM
// shared library, which means that when our freshly built llvm-config goes to load it's
// associated LLVM, it actually loads the compiler's LLVM. In particular when building the first
// compiler (i.e., in stage 0) that's a problem, as the compiler's LLVM is likely different from
// the one we want to use. As such, we restore the environment to what bootstrap saw. This isn't
// perfect -- we might actually want to see something from Cargo's added library paths -- but
// for now it works.
pub fn restore_library_path() {
    println!("cargo:rerun-if-env-changed=REAL_LIBRARY_PATH_VAR");
    println!("cargo:rerun-if-env-changed=REAL_LIBRARY_PATH");
    let key = env::var_os("REAL_LIBRARY_PATH_VAR").expect("REAL_LIBRARY_PATH_VAR");
    if let Some(env) = env::var_os("REAL_LIBRARY_PATH") {
        env::set_var(&key, &env);
    } else {
        env::remove_var(&key);
    }
}

/// Run the command, printing what we are running.
pub fn run_verbose(cmd: &mut Command) {
    println!("running: {:?}", cmd);
    run(cmd);
}

pub fn run(cmd: &mut Command) {
    if !try_run(cmd) {
        std::process::exit(1);
    }
}

pub fn try_run(cmd: &mut Command) -> bool {
    let status = match cmd.status() {
        Ok(status) => status,
        Err(e) => fail(&format!(
            "failed to execute command: {:?}\nerror: {}",
            cmd, e
        )),
    };
    if !status.success() {
        println!(
            "\n\ncommand did not execute successfully: {:?}\n\
             expected success, got: {}\n\n",
            cmd, status
        );
    }
    status.success()
}

pub fn run_suppressed(cmd: &mut Command) {
    if !try_run_suppressed(cmd) {
        std::process::exit(1);
    }
}

pub fn try_run_suppressed(cmd: &mut Command) -> bool {
    let output = match cmd.output() {
        Ok(status) => status,
        Err(e) => fail(&format!(
            "failed to execute command: {:?}\nerror: {}",
            cmd, e
        )),
    };
    if !output.status.success() {
        println!(
            "\n\ncommand did not execute successfully: {:?}\n\
             expected success, got: {}\n\n\
             stdout ----\n{}\n\
             stderr ----\n{}\n\n",
            cmd,
            output.status,
            String::from_utf8_lossy(&output.stdout),
            String::from_utf8_lossy(&output.stderr)
        );
    }
    output.status.success()
}

pub fn gnu_target(target: &str) -> &str {
    match target {
        "i686-pc-windows-msvc" => "i686-pc-win32",
        "x86_64-pc-windows-msvc" => "x86_64-pc-win32",
        "i686-pc-windows-gnu" => "i686-w64-mingw32",
        "x86_64-pc-windows-gnu" => "x86_64-w64-mingw32",
        s => s,
    }
}

pub fn make(host: &str) -> PathBuf {
    if host.contains("dragonfly") || host.contains("freebsd")
        || host.contains("netbsd") || host.contains("openbsd")
    {
        PathBuf::from("gmake")
    } else {
        PathBuf::from("make")
    }
}

pub fn output(cmd: &mut Command) -> String {
    let output = match cmd.stderr(Stdio::inherit()).output() {
        Ok(status) => status,
        Err(e) => fail(&format!(
            "failed to execute command: {:?}\nerror: {}",
            cmd, e
        )),
    };
    if !output.status.success() {
        panic!(
            "command did not execute successfully: {:?}\n\
             expected success, got: {}",
            cmd, output.status
        );
    }
    String::from_utf8(output.stdout).unwrap()
}

pub fn rerun_if_changed_anything_in_dir(dir: &Path) {
    let mut stack = dir.read_dir()
        .unwrap()
        .map(|e| e.unwrap())
        .filter(|e| &*e.file_name() != ".git")
        .collect::<Vec<_>>();
    while let Some(entry) = stack.pop() {
        let path = entry.path();
        if entry.file_type().unwrap().is_dir() {
            stack.extend(path.read_dir().unwrap().map(|e| e.unwrap()));
        } else {
            println!("cargo:rerun-if-changed={}", path.display());
        }
    }
}

/// Returns the last-modified time for `path`, or zero if it doesn't exist.
pub fn mtime(path: &Path) -> SystemTime {
    fs::metadata(path)
        .and_then(|f| f.modified())
        .unwrap_or(UNIX_EPOCH)
}

/// Returns `true` if `dst` is up to date given that the file or files in `src`
/// are used to generate it.
///
/// Uses last-modified time checks to verify this.
pub fn up_to_date(src: &Path, dst: &Path) -> bool {
    if !dst.exists() {
        return false;
    }
    let threshold = mtime(dst);
    let meta = match fs::metadata(src) {
        Ok(meta) => meta,
        Err(e) => panic!("source {:?} failed to get metadata: {}", src, e),
    };
    if meta.is_dir() {
        dir_up_to_date(src, threshold)
    } else {
        meta.modified().unwrap_or(UNIX_EPOCH) <= threshold
    }
}

#[must_use]
pub struct NativeLibBoilerplate {
    pub src_dir: PathBuf,
    pub out_dir: PathBuf,
}

impl NativeLibBoilerplate {
    /// On macOS we don't want to ship the exact filename that compiler-rt builds.
    /// This conflicts with the system and ours is likely a wildly different
    /// version, so they can't be substituted.
    ///
    /// As a result, we rename it here but we need to also use
    /// `install_name_tool` on macOS to rename the commands listed inside of it to
    /// ensure it's linked against correctly.
    pub fn fixup_sanitizer_lib_name(&self, sanitizer_name: &str) {
        if env::var("TARGET").unwrap() != "x86_64-apple-darwin" {
            return
        }

        let dir = self.out_dir.join("build/lib/darwin");
        let name = format!("clang_rt.{}_osx_dynamic", sanitizer_name);
        let src = dir.join(&format!("lib{}.dylib", name));
        let new_name = format!("lib__rustc__{}.dylib", name);
        let dst = dir.join(&new_name);

        println!("{} => {}", src.display(), dst.display());
        fs::rename(&src, &dst).unwrap();
        let status = Command::new("install_name_tool")
            .arg("-id")
            .arg(format!("@rpath/{}", new_name))
            .arg(&dst)
            .status()
            .expect("failed to execute `install_name_tool`");
        assert!(status.success());
    }
}

impl Drop for NativeLibBoilerplate {
    fn drop(&mut self) {
        if !thread::panicking() {
            t!(File::create(self.out_dir.join("rustbuild.timestamp")));
        }
    }
}

// Perform standard preparations for native libraries that are build only once for all stages.
// Emit rerun-if-changed and linking attributes for Cargo, check if any source files are
// updated, calculate paths used later in actual build with CMake/make or C/C++ compiler.
// If Err is returned, then everything is up-to-date and further build actions can be skipped.
// Timestamps are created automatically when the result of `native_lib_boilerplate` goes out
// of scope, so all the build actions should be completed until then.
pub fn native_lib_boilerplate(
    src_dir: &Path,
    out_name: &str,
    link_name: &str,
    search_subdir: &str,
) -> Result<NativeLibBoilerplate, ()> {
    rerun_if_changed_anything_in_dir(src_dir);

    let out_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or_else(||
        env::var_os("OUT_DIR").unwrap());
    let out_dir = PathBuf::from(out_dir).join(out_name);
    t!(fs::create_dir_all(&out_dir));
    if link_name.contains('=') {
        println!("cargo:rustc-link-lib={}", link_name);
    } else {
        println!("cargo:rustc-link-lib=static={}", link_name);
    }
    println!(
        "cargo:rustc-link-search=native={}",
        out_dir.join(search_subdir).display()
    );

    let timestamp = out_dir.join("rustbuild.timestamp");
    if !up_to_date(Path::new("build.rs"), &timestamp) || !up_to_date(src_dir, &timestamp) {
        Ok(NativeLibBoilerplate {
            src_dir: src_dir.to_path_buf(),
            out_dir: out_dir,
        })
    } else {
        Err(())
    }
}

pub fn sanitizer_lib_boilerplate(sanitizer_name: &str)
    -> Result<(NativeLibBoilerplate, String), ()>
{
    let (link_name, search_path, apple) = match &*env::var("TARGET").unwrap() {
        "x86_64-unknown-linux-gnu" => (
            format!("clang_rt.{}-x86_64", sanitizer_name),
            "build/lib/linux",
            false,
        ),
        "x86_64-apple-darwin" => (
            format!("clang_rt.{}_osx_dynamic", sanitizer_name),
            "build/lib/darwin",
            true,
        ),
        _ => return Err(()),
    };
    let to_link = if apple {
        format!("dylib=__rustc__{}", link_name)
    } else {
        format!("static={}", link_name)
    };
    // This env var is provided by rustbuild to tell us where `compiler-rt`
    // lives.
    let dir = env::var_os("RUST_COMPILER_RT_ROOT").unwrap();
    let lib = native_lib_boilerplate(
        dir.as_ref(),
        sanitizer_name,
        &to_link,
        search_path,
    )?;
    Ok((lib, link_name))
}

fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool {
    t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| {
        let meta = t!(e.metadata());
        if meta.is_dir() {
            dir_up_to_date(&e.path(), threshold)
        } else {
            meta.modified().unwrap_or(UNIX_EPOCH) < threshold
        }
    })
}

fn fail(s: &str) -> ! {
    println!("\n\n{}\n\n", s);
    std::process::exit(1);
}
<commit_msg>Apply clippy::redundant_field_names suggestion<commit_after>// NO-RUSTC-WRAPPER
#![deny(warnings, rust_2018_idioms, unused_lifetimes)]

use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::time::{SystemTime, UNIX_EPOCH};
use std::{env, fs};
use std::thread;

/// A helper macro to `unwrap` a result except also print out details like:
///
/// * The file/line of the panic
/// * The expression that failed
/// * The error itself
///
/// This is currently used judiciously throughout the build system rather than
/// using a `Result` with `try!`, but this may change one day...
#[macro_export]
macro_rules! t {
    ($e:expr) => {
        match $e {
            Ok(e) => e,
            Err(e) => panic!("{} failed with {}", stringify!($e), e),
        }
    };
}

// Because Cargo adds the compiler's dylib path to our library search path, llvm-config may
// break: the dylib path for the compiler, as of this writing, contains a copy of the LLVM
// shared library, which means that when our freshly built llvm-config goes to load it's
// associated LLVM, it actually loads the compiler's LLVM. In particular when building the first
// compiler (i.e., in stage 0) that's a problem, as the compiler's LLVM is likely different from
// the one we want to use. As such, we restore the environment to what bootstrap saw. This isn't
// perfect -- we might actually want to see something from Cargo's added library paths -- but
// for now it works.
pub fn restore_library_path() {
    println!("cargo:rerun-if-env-changed=REAL_LIBRARY_PATH_VAR");
    println!("cargo:rerun-if-env-changed=REAL_LIBRARY_PATH");
    let key = env::var_os("REAL_LIBRARY_PATH_VAR").expect("REAL_LIBRARY_PATH_VAR");
    if let Some(env) = env::var_os("REAL_LIBRARY_PATH") {
        env::set_var(&key, &env);
    } else {
        env::remove_var(&key);
    }
}

/// Run the command, printing what we are running.
pub fn run_verbose(cmd: &mut Command) {
    println!("running: {:?}", cmd);
    run(cmd);
}

pub fn run(cmd: &mut Command) {
    if !try_run(cmd) {
        std::process::exit(1);
    }
}

pub fn try_run(cmd: &mut Command) -> bool {
    let status = match cmd.status() {
        Ok(status) => status,
        Err(e) => fail(&format!(
            "failed to execute command: {:?}\nerror: {}",
            cmd, e
        )),
    };
    if !status.success() {
        println!(
            "\n\ncommand did not execute successfully: {:?}\n\
             expected success, got: {}\n\n",
            cmd, status
        );
    }
    status.success()
}

pub fn run_suppressed(cmd: &mut Command) {
    if !try_run_suppressed(cmd) {
        std::process::exit(1);
    }
}

pub fn try_run_suppressed(cmd: &mut Command) -> bool {
    let output = match cmd.output() {
        Ok(status) => status,
        Err(e) => fail(&format!(
            "failed to execute command: {:?}\nerror: {}",
            cmd, e
        )),
    };
    if !output.status.success() {
        println!(
            "\n\ncommand did not execute successfully: {:?}\n\
             expected success, got: {}\n\n\
             stdout ----\n{}\n\
             stderr ----\n{}\n\n",
            cmd,
            output.status,
            String::from_utf8_lossy(&output.stdout),
            String::from_utf8_lossy(&output.stderr)
        );
    }
    output.status.success()
}

pub fn gnu_target(target: &str) -> &str {
    match target {
        "i686-pc-windows-msvc" => "i686-pc-win32",
        "x86_64-pc-windows-msvc" => "x86_64-pc-win32",
        "i686-pc-windows-gnu" => "i686-w64-mingw32",
        "x86_64-pc-windows-gnu" => "x86_64-w64-mingw32",
        s => s,
    }
}

pub fn make(host: &str) -> PathBuf {
    if host.contains("dragonfly") || host.contains("freebsd")
        || host.contains("netbsd") || host.contains("openbsd")
    {
        PathBuf::from("gmake")
    } else {
        PathBuf::from("make")
    }
}

pub fn output(cmd: &mut Command) -> String {
    let output = match cmd.stderr(Stdio::inherit()).output() {
        Ok(status) => status,
        Err(e) => fail(&format!(
            "failed to execute command: {:?}\nerror: {}",
            cmd, e
        )),
    };
    if !output.status.success() {
        panic!(
            "command did not execute successfully: {:?}\n\
             expected success, got: {}",
            cmd, output.status
        );
    }
    String::from_utf8(output.stdout).unwrap()
}

pub fn rerun_if_changed_anything_in_dir(dir: &Path) {
    let mut stack = dir.read_dir()
        .unwrap()
        .map(|e| e.unwrap())
        .filter(|e| &*e.file_name() != ".git")
        .collect::<Vec<_>>();
    while let Some(entry) = stack.pop() {
        let path = entry.path();
        if entry.file_type().unwrap().is_dir() {
            stack.extend(path.read_dir().unwrap().map(|e| e.unwrap()));
        } else {
            println!("cargo:rerun-if-changed={}", path.display());
        }
    }
}

/// Returns the last-modified time for `path`, or zero if it doesn't exist.
pub fn mtime(path: &Path) -> SystemTime {
    fs::metadata(path)
        .and_then(|f| f.modified())
        .unwrap_or(UNIX_EPOCH)
}

/// Returns `true` if `dst` is up to date given that the file or files in `src`
/// are used to generate it.
///
/// Uses last-modified time checks to verify this.
pub fn up_to_date(src: &Path, dst: &Path) -> bool {
    if !dst.exists() {
        return false;
    }
    let threshold = mtime(dst);
    let meta = match fs::metadata(src) {
        Ok(meta) => meta,
        Err(e) => panic!("source {:?} failed to get metadata: {}", src, e),
    };
    if meta.is_dir() {
        dir_up_to_date(src, threshold)
    } else {
        meta.modified().unwrap_or(UNIX_EPOCH) <= threshold
    }
}

#[must_use]
pub struct NativeLibBoilerplate {
    pub src_dir: PathBuf,
    pub out_dir: PathBuf,
}

impl NativeLibBoilerplate {
    /// On macOS we don't want to ship the exact filename that compiler-rt builds.
    /// This conflicts with the system and ours is likely a wildly different
    /// version, so they can't be substituted.
    ///
    /// As a result, we rename it here but we need to also use
    /// `install_name_tool` on macOS to rename the commands listed inside of it to
    /// ensure it's linked against correctly.
    pub fn fixup_sanitizer_lib_name(&self, sanitizer_name: &str) {
        if env::var("TARGET").unwrap() != "x86_64-apple-darwin" {
            return
        }

        let dir = self.out_dir.join("build/lib/darwin");
        let name = format!("clang_rt.{}_osx_dynamic", sanitizer_name);
        let src = dir.join(&format!("lib{}.dylib", name));
        let new_name = format!("lib__rustc__{}.dylib", name);
        let dst = dir.join(&new_name);

        println!("{} => {}", src.display(), dst.display());
        fs::rename(&src, &dst).unwrap();
        let status = Command::new("install_name_tool")
            .arg("-id")
            .arg(format!("@rpath/{}", new_name))
            .arg(&dst)
            .status()
            .expect("failed to execute `install_name_tool`");
        assert!(status.success());
    }
}

impl Drop for NativeLibBoilerplate {
    fn drop(&mut self) {
        if !thread::panicking() {
            t!(File::create(self.out_dir.join("rustbuild.timestamp")));
        }
    }
}

// Perform standard preparations for native libraries that are build only once for all stages.
// Emit rerun-if-changed and linking attributes for Cargo, check if any source files are
// updated, calculate paths used later in actual build with CMake/make or C/C++ compiler.
// If Err is returned, then everything is up-to-date and further build actions can be skipped.
// Timestamps are created automatically when the result of `native_lib_boilerplate` goes out
// of scope, so all the build actions should be completed until then.
pub fn native_lib_boilerplate(
    src_dir: &Path,
    out_name: &str,
    link_name: &str,
    search_subdir: &str,
) -> Result<NativeLibBoilerplate, ()> {
    rerun_if_changed_anything_in_dir(src_dir);

    let out_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or_else(||
        env::var_os("OUT_DIR").unwrap());
    let out_dir = PathBuf::from(out_dir).join(out_name);
    t!(fs::create_dir_all(&out_dir));
    if link_name.contains('=') {
        println!("cargo:rustc-link-lib={}", link_name);
    } else {
        println!("cargo:rustc-link-lib=static={}", link_name);
    }
    println!(
        "cargo:rustc-link-search=native={}",
        out_dir.join(search_subdir).display()
    );

    let timestamp = out_dir.join("rustbuild.timestamp");
    if !up_to_date(Path::new("build.rs"), &timestamp) || !up_to_date(src_dir, &timestamp) {
        Ok(NativeLibBoilerplate {
            src_dir: src_dir.to_path_buf(),
            out_dir,
        })
    } else {
        Err(())
    }
}

pub fn sanitizer_lib_boilerplate(sanitizer_name: &str)
    -> Result<(NativeLibBoilerplate, String), ()>
{
    let (link_name, search_path, apple) = match &*env::var("TARGET").unwrap() {
        "x86_64-unknown-linux-gnu" => (
            format!("clang_rt.{}-x86_64", sanitizer_name),
            "build/lib/linux",
            false,
        ),
        "x86_64-apple-darwin" => (
            format!("clang_rt.{}_osx_dynamic", sanitizer_name),
            "build/lib/darwin",
            true,
        ),
        _ => return Err(()),
    };
    let to_link = if apple {
        format!("dylib=__rustc__{}", link_name)
    } else {
        format!("static={}", link_name)
    };
    // This env var is provided by rustbuild to tell us where `compiler-rt`
    // lives.
    let dir = env::var_os("RUST_COMPILER_RT_ROOT").unwrap();
    let lib = native_lib_boilerplate(
        dir.as_ref(),
        sanitizer_name,
        &to_link,
        search_path,
    )?;
    Ok((lib, link_name))
}

fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool {
    t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| {
        let meta = t!(e.metadata());
        if meta.is_dir() {
            dir_up_to_date(&e.path(), threshold)
        } else {
            meta.modified().unwrap_or(UNIX_EPOCH) < threshold
        }
    })
}

fn fail(s: &str) -> ! {
    println!("\n\n{}\n\n", s);
    std::process::exit(1);
}
<|endoftext|>


<commit_before>#![cfg_attr(feature="parse-generics-poc", feature(plugin))]
#![cfg_attr(feature="parse-generics-poc", plugin(parse_generics_poc))]
#[macro_use] extern crate parse_generics_shim;

#[macro_use] mod parse_enum;
#[macro_use] mod parse_item;
#[macro_use] mod parse_macros_util;
#[macro_use] mod parse_struct;
<commit_msg>Add docs to parse-macros.<commit_after>/*!
This crate provides high-level macros for parsing various Rust constructs.

Specifically, these macros are concerned with taking Rust source constructs and rewriting them into a format which is more easily consumable by `macro_rules!` macros.

## Table of Contents

- [`parse_enum!`](#parse_enum)
- [`parse_item!`](#parse_item)
- [`parse_struct!`](#parse_struct)

## `parse_enum!`

```ignore
macro_rules! parse_enum {
    (
        then $cb:ident!( $($cb_arg:tt)* ),
        $($body:tt)*
    ) => { ... };
}
```

Parses `$body` as an `enum`, invoking the macro `$cb` with the result.  The general form of the expansion is:

```ignore
$cb! {
    $($cb_arg)*
    enum {
        attrs: $attrs,
        vis: $vis,
        name: $name,
        generics: $generics,
        where: $where_,
        variants: $variants,
        num_variants: $num_variants,
    }
}
```

### Callback

`$cb_name` and `$cb_arg` specify the macro to invoke with the result of parsing.  Note that `$cb_arg` may be contained in *any* of `( .. )`, `[ .. ]`, or `{ .. }`.

### Fields

The expansion contains the following fields:

- `$attrs`: a `[ .. ]`-delimited list of attributes.  *e.g.*: `[ #[doc="Does a thing"] #[repr(u8)] ]`.

- `$vis`: a `( .. )`-delimited visibility annotation.  *e.g.*: `()`, `(pub)`.

- `$name`: the `enum`'s name as an identifier.  *e.g.*: `Option`.

- `$generics`: the `{ .. }`-delimited output of `parse_generics_shim!` for the `enum`, containing the `constr`, `params`, `ltimes`, and `tnames` fields:

    ```ignore
    generics: {
        constr: $constr,
        params: $params,
        ltimes: $ltimes,
        tnames: $tnames,
    }
    ```

    - `$constr`: a `[ .. ]`-delimited, comma-terminated list of generic constraints.  *e.g.* `['a, 'b: 'a, T, U: 'a + Copy,]`.

    - `$params`: a `[ .. ]`-delimited, comma-terminated list of generic parameter names.  *e.g.* `['a, 'b, T, U,]`.

    - `$ltimes`: a `[ .. ]`-delimited, comma-terminated list of generic lifetime parameters.  *e.g.* `['a, 'b,]`.

    - `$tnames`: a `[ .. ]`-delimited, comma-terminated list of generic type parameters.  *e.g.* `[T, U,]`.

- `$where_`: the `{ .. }`-delimited output of `parse_where_shim!` for the `enum`, containing the `preds` field:

    ```ignore
    where: {
        preds: $preds,
    }
    ```

    - `$preds`: a `[ .. ]`-delimited, comma-separated list of clause predicates.  *e.g.* `[ for<'a> T: Fn(&'a i32), ]`.

- `$variants`: a `[ .. ]`-delimited, comma-terminated list of variants (described below).

- `$num_variants`: the number of variants in the `enum`.  *e.g.* `2`.

Each variant has the following form:

```ignore
{
    ord: ($vord_index, $vord_ident),
    attrs: $vattrs,
    kind: $vkind,
    name: $vname,
    fields: $vfields,
    num_fields: $vnum_fields,
}
```

- `$vord_index`: the 0-based ordinal for this variant.  *e.g.* `1`.

- `$vord_ident`: an identifier guaranteed to be unique relative to other variants *for the same `enum`*.  Identifiers are *not* guaranteed to be unique between different `parse_enum!` invocations.  *e.g.* `_ord_01`.

- `$vattrs`: a `[ .. ]`-delimited list of attributes attached to the variant.  *e.g.* `[ #[doc="A variant unlike the rest."] ]`.

- `$vkind`: one of `unitary`, `tuple`, or `record`.

- `$vname`: the variant's name as an identifier.  *e.g.* `None`.

- `$vfields`: a `[ .. ]`-delimited, comma-terminated list of fields (described below).

- `$vnum_fields`: the number of fields in the variant.  *e.g.* `1`.

Variant fields have the following form:

```ignore
{
    ord: ($ford_index, $ford_ident),
    attrs: $fattrs,
    vis: $fvis,
    ty: $fty,

    // **NOTE**: only exists for *record* variant fields:
    name: $fname,
}
```

- `$ford_index`: the 0-based ordinal for this variant field.  *e.g.* `1`.

- `$ford_ident`: an identifier guaranteed to be unique relative to other fields *for the same variant*.  Identifiers are *not* guaranteed to be unique between different `parse_enum!` invocations, or between variants in the same invocation.  *e.g.* `_ord_01`.

- `$fattrs`: a `[ .. ]`-delimited list of attributes attached to the variant field.  *e.g.* `[ #[doc="A part of the whole."] ]`.

- `$fvis`: a `( .. )`-delimited visibility annotation.  *e.g.*: `()`, `(pub)`.

- `$fty`: the type of the variant field.

- `$fname`: the variant field's name as an identifier.  *e.g.* `part`.

### Example

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# #[macro_use] extern crate parse_macros;
# fn main() {
# assert_eq!( (
parse_enum! {
    then stringify!(output:),
    /// The `Option` type.
    pub enum Option<T> {
        /// No value.
        None,
        /// Some value `T`.
        Some(T),
        /// File could not be found.
        FileNotFound { path: PathBuf },
    }
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , r#"
    output:
    enum {
        attrs: [ #[doc=r"The `Option` type."] ],
        vis: (pub),
        name: Option,
        generics: {
            constr: [T,],
            params: [T,],
            ltimes: [],
            tnames: [T,],
        },
        where: {
            preds: [],
        },
        variants: [
            {
                ord: (0, _ord_00),
                attrs: [ #[doc=r"No value."] ],
                kind: unitary,
                name: None,
                fields: [],
                num_fields: 0,
            },
            {
                ord: (1, _ord_01),
                attrs: [ #[doc=r"Some value `T`."] ],
                kind: tuple,
                name: Some,
                fields: [
                    {
                        ord: (0, _ord_00),
                        attrs: [],
                        vis: (),
                        ty: T,
                    },
                ],
                num_fields: 1,
            },
            {
                ord: (2, _ord_02),
                attrs: [ #[doc=r"File could not be found."] ],
                kind: record,
                name: FileNotFound,
                fields: [
                    {
                        ord: (0, _ord_00),
                        attrs: [],
                        vis: (),
                        ty: PathBuf,
                        name: path,
                    },
                ],
                num_fields: 1,
            },
        ],
        num_variants: 3,
    }
# "#.replace(char::is_whitespace, "")); /*
)
# */ }
```

## `parse_item!`

```ignore
macro_rules! parse_item {
    (
        then $cb:ident!( $($cb_arg:tt)* ),
        $($body:tt)*
    ) => { ... };
}
```

Parses `$body` as an item, invoking the macro `$cb` with the result.  This forwards to the appropriate `parse_*!` macro, depending on what kind of item is in `$body`.

See [`parse_enum!`](#parse_enum), and [`parse_struct!`](#parse_struct) for more details.

## `parse_struct!`

```ignore
macro_rules! parse_struct {
    (
        then $cb:ident!( $($cb_arg:tt)* ),
        $($body:tt)*
    ) => { ... };
}
```

Parses `$body` as a `struct`, invoking the macro `$cb` with the result.  The general form of the expansion is:

```ignore
$cb! {
    $($cb_arg)*
    struct {
        attrs: $attrs,
        vis: $vis,
        name: $name,
        generics: $generics,
        where: $where_,
        kind: $kind,
        fields: $fields,
        num_fields: $num_fields,
    }
}
```

### Callback

`$cb_name` and `$cb_arg` specify the macro to invoke with the result of parsing.  Note that `$cb_arg` may be contained in *any* of `( .. )`, `[ .. ]`, or `{ .. }`.

### Fields

The expansion contains the following fields:

- `$attrs`: a `[ .. ]`-delimited list of attributes.  *e.g.*: `[ #[doc="Does a thing"] #[repr(C)] ]`.

- `$vis`: a `( .. )`-delimited visibility annotation.  *e.g.*: `()`, `(pub)`.

- `$name`: the `struct`'s name as an identifier.  *e.g.*: `Option`.

- `$generics`: the `{ .. }`-delimited output of `parse_generics_shim!` for the `struct`, containing the `constr`, `params`, `ltimes`, and `tnames` fields:

    ```ignore
    generics: {
        constr: $constr,
        params: $params,
        ltimes: $ltimes,
        tnames: $tnames,
    }
    ```

    - `$constr`: a `[ .. ]`-delimited, comma-terminated list of generic constraints.  *e.g.* `['a, 'b: 'a, T, U: 'a + Copy,]`.

    - `$params`: a `[ .. ]`-delimited, comma-terminated list of generic parameter names.  *e.g.* `['a, 'b, T, U,]`.

    - `$ltimes`: a `[ .. ]`-delimited, comma-terminated list of generic lifetime parameters.  *e.g.* `['a, 'b,]`.

    - `$tnames`: a `[ .. ]`-delimited, comma-terminated list of generic type parameters.  *e.g.* `[T, U,]`.

- `$where_`: the `{ .. }`-delimited output of `parse_where_shim!` for the `struct`, containing the `preds` field:

    ```ignore
    where: {
        preds: $preds,
    }
    ```

    - `$preds`: a `[ .. ]`-delimited, comma-separated list of clause predicates.  *e.g.* `[ for<'a> T: Fn(&'a i32), ]`.

- `$kind`: one of `unitary`, `tuple`, or `record`.  These correspond to the three kinds of `struct` definitions: `struct Unitary;`, `struct Tuple(..);` and `struct Record { .. }`.

- `$fields`: a `[ .. ]`-delimited, comma-terminated list of fields (described below).

- `$num_fields`: the number of fields in the `struct`.  *e.g.* `2`.

`struct` fields have the following form:

```ignore
{
    ord: ($ford_index, $ford_ident),
    attrs: $fattrs,
    vis: $fvis,
    ty: $fty,

    // **NOTE**: only exists for *record* `struct` fields:
    name: $fname,
}
```

- `$ford_index`: the 0-based ordinal for this `struct` field.  *e.g.* `1`.

- `$ford_ident`: an identifier guaranteed to be unique relative to other fields *for the same `struct`*.  Identifiers are *not* guaranteed to be unique between different `parse_struct!` invocations.  *e.g.* `_ord_01`.

- `$fattrs`: a `[ .. ]`-delimited list of attributes attached to the `struct` field.  *e.g.* `[ #[doc="The amount of green-ness."] ]`.

- `$fvis`: a `( .. )`-delimited visibility annotation.  *e.g.*: `()`, `(pub)`.

- `$fty`: the type of the `struct` field.

- `$fname`: the `struct` field's name as an identifier.  *e.g.* `green`.

### Example

```rust
# #![cfg_attr(feature="use-parse-generics-poc", feature(plugin))]
# #![cfg_attr(feature="use-parse-generics-poc", plugin(parse_generics_poc))]
# #[macro_use] extern crate parse_generics_shim;
# #[macro_use] extern crate parse_macros;
# fn main() {
# assert_eq!( (
parse_struct! {
    then stringify!(output:),
    /// Represents a colour.
    pub struct Rgb<Ch> {
        /// The degree of red-ness.
        r: Ch,
        /// How eco-friendly is this colour?
        g: Ch,
        /// Maybe it's blue, maybe it's not?
        b: Option<Ch>,
    }
}

// Expands to:
# /*
stringify!(
# */
# ).replace(char::is_whitespace, "") , r#"
    output:
    struct {
        attrs: [ #[doc=r"Represents a colour."] ],
        vis: (pub),
        name: Rgb,
        generics: {
            constr: [Ch,],
            params: [Ch,],
            ltimes: [],
            tnames: [Ch,],
        },
        where: {
            preds: [],
        },
        kind: record,
        fields: [
            {
                ord: (0, _ord_00),
                attrs: [ #[doc=r"The degree of red-ness."] ],
                vis: (),
                ty: Ch,
                name: r,
            },
            {
                ord: (1, _ord_01),
                attrs: [ #[doc=r"How eco-friendly is this colour?"] ],
                vis: (),
                ty: Ch,
                name: g,
            },
            {
                ord: (2, _ord_02),
                attrs: [ #[doc=r"Maybe it's blue, maybe it's not?"] ],
                vis: (),
                ty: Option<Ch>,
                name: b,
            },
        ],
        num_fields: 3,
    }
# "#.replace(char::is_whitespace, "")); /*
)
# */ }
```
*/
#![cfg_attr(feature="parse-generics-poc", feature(plugin))]
#![cfg_attr(feature="parse-generics-poc", plugin(parse_generics_poc))]
#[macro_use] extern crate parse_generics_shim;

#[macro_use] mod parse_enum;
#[macro_use] mod parse_item;
#[macro_use] mod parse_macros_util;
#[macro_use] mod parse_struct;
<|endoftext|>


<commit_before>use std::fs::{File, OpenOptions};
use std::io;
use std::io::{Read, Seek, SeekFrom, Write};
use std::path::{Display, Path, PathBuf};

use fs2::{lock_contended_error, FileExt};
#[allow(unused_imports)]
use libc;
use termcolor::Color::Cyan;

use crate::util::errors::{CargoResult, CargoResultExt};
use crate::util::paths;
use crate::util::Config;

#[derive(Debug)]
pub struct FileLock {
    f: Option<File>,
    path: PathBuf,
    state: State,
}

#[derive(PartialEq, Debug)]
enum State {
    Unlocked,
    Shared,
    Exclusive,
}

impl FileLock {
    /// Returns the underlying file handle of this lock.
    pub fn file(&self) -> &File {
        self.f.as_ref().unwrap()
    }

    /// Returns the underlying path that this lock points to.
    ///
    /// Note that special care must be taken to ensure that the path is not
    /// referenced outside the lifetime of this lock.
    pub fn path(&self) -> &Path {
        assert_ne!(self.state, State::Unlocked);
        &self.path
    }

    /// Returns the parent path containing this file
    pub fn parent(&self) -> &Path {
        assert_ne!(self.state, State::Unlocked);
        self.path.parent().unwrap()
    }

    /// Removes all sibling files to this locked file.
    ///
    /// This can be useful if a directory is locked with a sentinel file but it
    /// needs to be cleared out as it may be corrupt.
    pub fn remove_siblings(&self) -> CargoResult<()> {
        let path = self.path();
        for entry in path.parent().unwrap().read_dir()? {
            let entry = entry?;
            if Some(&entry.file_name()[..]) == path.file_name() {
                continue;
            }
            let kind = entry.file_type()?;
            if kind.is_dir() {
                paths::remove_dir_all(entry.path())?;
            } else {
                paths::remove_file(entry.path())?;
            }
        }
        Ok(())
    }
}

impl Read for FileLock {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.file().read(buf)
    }
}

impl Seek for FileLock {
    fn seek(&mut self, to: SeekFrom) -> io::Result<u64> {
        self.file().seek(to)
    }
}

impl Write for FileLock {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.file().write(buf)
    }

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

impl Drop for FileLock {
    fn drop(&mut self) {
        if self.state != State::Unlocked {
            if let Some(f) = self.f.take() {
                let _ = f.unlock();
            }
        }
    }
}

/// A "filesystem" is intended to be a globally shared, hence locked, resource
/// in Cargo.
///
/// The `Path` of a filesystem cannot be learned unless it's done in a locked
/// fashion, and otherwise functions on this structure are prepared to handle
/// concurrent invocations across multiple instances of Cargo.
#[derive(Clone, Debug)]
pub struct Filesystem {
    root: PathBuf,
}

impl Filesystem {
    /// Creates a new filesystem to be rooted at the given path.
    pub fn new(path: PathBuf) -> Filesystem {
        Filesystem { root: path }
    }

    /// Like `Path::join`, creates a new filesystem rooted at this filesystem
    /// joined with the given path.
    pub fn join<T: AsRef<Path>>(&self, other: T) -> Filesystem {
        Filesystem::new(self.root.join(other))
    }

    /// Like `Path::push`, pushes a new path component onto this filesystem.
    pub fn push<T: AsRef<Path>>(&mut self, other: T) {
        self.root.push(other);
    }

    /// Consumes this filesystem and returns the underlying `PathBuf`.
    ///
    /// Note that this is a relatively dangerous operation and should be used
    /// with great caution!.
    pub fn into_path_unlocked(self) -> PathBuf {
        self.root
    }

    /// Returns the underlying `Path`.
    ///
    /// Note that this is a relatively dangerous operation and should be used
    /// with great caution!.
    pub fn as_path_unlocked(&self) -> &Path {
        &self.root
    }

    /// Creates the directory pointed to by this filesystem.
    ///
    /// Handles errors where other Cargo processes are also attempting to
    /// concurrently create this directory.
    pub fn create_dir(&self) -> CargoResult<()> {
        paths::create_dir_all(&self.root)?;
        Ok(())
    }

    /// Returns an adaptor that can be used to print the path of this
    /// filesystem.
    pub fn display(&self) -> Display<'_> {
        self.root.display()
    }

    /// Opens exclusive access to a file, returning the locked version of a
    /// file.
    ///
    /// This function will create a file at `path` if it doesn't already exist
    /// (including intermediate directories), and then it will acquire an
    /// exclusive lock on `path`. If the process must block waiting for the
    /// lock, the `msg` is printed to `config`.
    ///
    /// The returned file can be accessed to look at the path and also has
    /// read/write access to the underlying file.
    pub fn open_rw<P>(&self, path: P, config: &Config, msg: &str) -> CargoResult<FileLock>
    where
        P: AsRef<Path>,
    {
        self.open(
            path.as_ref(),
            OpenOptions::new().read(true).write(true).create(true),
            State::Exclusive,
            config,
            msg,
        )
    }

    /// Opens shared access to a file, returning the locked version of a file.
    ///
    /// This function will fail if `path` doesn't already exist, but if it does
    /// then it will acquire a shared lock on `path`. If the process must block
    /// waiting for the lock, the `msg` is printed to `config`.
    ///
    /// The returned file can be accessed to look at the path and also has read
    /// access to the underlying file. Any writes to the file will return an
    /// error.
    pub fn open_ro<P>(&self, path: P, config: &Config, msg: &str) -> CargoResult<FileLock>
    where
        P: AsRef<Path>,
    {
        self.open(
            path.as_ref(),
            OpenOptions::new().read(true),
            State::Shared,
            config,
            msg,
        )
    }

    fn open(
        &self,
        path: &Path,
        opts: &OpenOptions,
        state: State,
        config: &Config,
        msg: &str,
    ) -> CargoResult<FileLock> {
        let path = self.root.join(path);

        // If we want an exclusive lock then if we fail because of NotFound it's
        // likely because an intermediate directory didn't exist, so try to
        // create the directory and then continue.
        let f = opts
            .open(&path)
            .or_else(|e| {
                if e.kind() == io::ErrorKind::NotFound && state == State::Exclusive {
                    paths::create_dir_all(path.parent().unwrap())?;
                    Ok(opts.open(&path)?)
                } else {
                    Err(failure::Error::from(e))
                }
            })
            .chain_err(|| format!("failed to open: {}", path.display()))?;
        match state {
            State::Exclusive => {
                acquire(config, msg, &path, &|| f.try_lock_exclusive(), &|| {
                    f.lock_exclusive()
                })?;
            }
            State::Shared => {
                acquire(config, msg, &path, &|| f.try_lock_shared(), &|| {
                    f.lock_shared()
                })?;
            }
            State::Unlocked => {}
        }
        Ok(FileLock {
            f: Some(f),
            path,
            state,
        })
    }
}

impl PartialEq<Path> for Filesystem {
    fn eq(&self, other: &Path) -> bool {
        self.root == other
    }
}

impl PartialEq<Filesystem> for Path {
    fn eq(&self, other: &Filesystem) -> bool {
        self == other.root
    }
}

/// Acquires a lock on a file in a "nice" manner.
///
/// Almost all long-running blocking actions in Cargo have a status message
/// associated with them as we're not sure how long they'll take. Whenever a
/// conflicted file lock happens, this is the case (we're not sure when the lock
/// will be released).
///
/// This function will acquire the lock on a `path`, printing out a nice message
/// to the console if we have to wait for it. It will first attempt to use `try`
/// to acquire a lock on the crate, and in the case of contention it will emit a
/// status message based on `msg` to `config`'s shell, and then use `block` to
/// block waiting to acquire a lock.
///
/// Returns an error if the lock could not be acquired or if any error other
/// than a contention error happens.
fn acquire(
    config: &Config,
    msg: &str,
    path: &Path,
    r#try: &dyn Fn() -> io::Result<()>,
    block: &dyn Fn() -> io::Result<()>,
) -> CargoResult<()> {
    // File locking on Unix is currently implemented via `flock`, which is known
    // to be broken on NFS. We could in theory just ignore errors that happen on
    // NFS, but apparently the failure mode [1] for `flock` on NFS is **blocking
    // forever**, even if the "non-blocking" flag is passed!
    //
    // As a result, we just skip all file locks entirely on NFS mounts. That
    // should avoid calling any `flock` functions at all, and it wouldn't work
    // there anyway.
    //
    // [1]: https://github.com/rust-lang/cargo/issues/2615
    if is_on_nfs_mount(path) {
        return Ok(());
    }

    match r#try() {
        Ok(()) => return Ok(()),

        // In addition to ignoring NFS which is commonly not working we also
        // just ignore locking on filesystems that look like they don't
        // implement file locking. We detect that here via the return value of
        // locking (e.g., inspecting errno).
        #[cfg(unix)]
        Err(ref e) if e.raw_os_error() == Some(libc::ENOTSUP) => return Ok(()),

        #[cfg(target_os = "linux")]
        Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => return Ok(()),

        Err(e) => {
            if e.raw_os_error() != lock_contended_error().raw_os_error() {
                let e = failure::Error::from(e);
                let cx = format!("failed to lock file: {}", path.display());
                return Err(e.context(cx).into());
            }
        }
    }
    let msg = format!("waiting for file lock on {}", msg);
    config.shell().status_with_color("Blocking", &msg, Cyan)?;

    block().chain_err(|| format!("failed to lock file: {}", path.display()))?;
    return Ok(());

    #[cfg(all(target_os = "linux", not(target_env = "musl")))]
    fn is_on_nfs_mount(path: &Path) -> bool {
        use std::ffi::CString;
        use std::mem;
        use std::os::unix::prelude::*;

        let path = match CString::new(path.as_os_str().as_bytes()) {
            Ok(path) => path,
            Err(_) => return false,
        };

        unsafe {
            let mut buf: libc::statfs = mem::zeroed();
            let r = libc::statfs(path.as_ptr(), &mut buf);

            r == 0 && buf.f_type as u32 == libc::NFS_SUPER_MAGIC as u32
        }
    }

    #[cfg(any(not(target_os = "linux"), target_env = "musl"))]
    fn is_on_nfs_mount(_path: &Path) -> bool {
        false
    }
}
<commit_msg>Ignore file lock errors if unsupported, on Windows<commit_after>use std::fs::{File, OpenOptions};
use std::io;
use std::io::{Read, Seek, SeekFrom, Write};
use std::path::{Display, Path, PathBuf};

use fs2::{lock_contended_error, FileExt};
#[allow(unused_imports)]
use libc;
use termcolor::Color::Cyan;
#[cfg(windows)]
use winapi::shared::winerror::ERROR_INVALID_FUNCTION;

use crate::util::errors::{CargoResult, CargoResultExt};
use crate::util::paths;
use crate::util::Config;

#[derive(Debug)]
pub struct FileLock {
    f: Option<File>,
    path: PathBuf,
    state: State,
}

#[derive(PartialEq, Debug)]
enum State {
    Unlocked,
    Shared,
    Exclusive,
}

impl FileLock {
    /// Returns the underlying file handle of this lock.
    pub fn file(&self) -> &File {
        self.f.as_ref().unwrap()
    }

    /// Returns the underlying path that this lock points to.
    ///
    /// Note that special care must be taken to ensure that the path is not
    /// referenced outside the lifetime of this lock.
    pub fn path(&self) -> &Path {
        assert_ne!(self.state, State::Unlocked);
        &self.path
    }

    /// Returns the parent path containing this file
    pub fn parent(&self) -> &Path {
        assert_ne!(self.state, State::Unlocked);
        self.path.parent().unwrap()
    }

    /// Removes all sibling files to this locked file.
    ///
    /// This can be useful if a directory is locked with a sentinel file but it
    /// needs to be cleared out as it may be corrupt.
    pub fn remove_siblings(&self) -> CargoResult<()> {
        let path = self.path();
        for entry in path.parent().unwrap().read_dir()? {
            let entry = entry?;
            if Some(&entry.file_name()[..]) == path.file_name() {
                continue;
            }
            let kind = entry.file_type()?;
            if kind.is_dir() {
                paths::remove_dir_all(entry.path())?;
            } else {
                paths::remove_file(entry.path())?;
            }
        }
        Ok(())
    }
}

impl Read for FileLock {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.file().read(buf)
    }
}

impl Seek for FileLock {
    fn seek(&mut self, to: SeekFrom) -> io::Result<u64> {
        self.file().seek(to)
    }
}

impl Write for FileLock {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.file().write(buf)
    }

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

impl Drop for FileLock {
    fn drop(&mut self) {
        if self.state != State::Unlocked {
            if let Some(f) = self.f.take() {
                let _ = f.unlock();
            }
        }
    }
}

/// A "filesystem" is intended to be a globally shared, hence locked, resource
/// in Cargo.
///
/// The `Path` of a filesystem cannot be learned unless it's done in a locked
/// fashion, and otherwise functions on this structure are prepared to handle
/// concurrent invocations across multiple instances of Cargo.
#[derive(Clone, Debug)]
pub struct Filesystem {
    root: PathBuf,
}

impl Filesystem {
    /// Creates a new filesystem to be rooted at the given path.
    pub fn new(path: PathBuf) -> Filesystem {
        Filesystem { root: path }
    }

    /// Like `Path::join`, creates a new filesystem rooted at this filesystem
    /// joined with the given path.
    pub fn join<T: AsRef<Path>>(&self, other: T) -> Filesystem {
        Filesystem::new(self.root.join(other))
    }

    /// Like `Path::push`, pushes a new path component onto this filesystem.
    pub fn push<T: AsRef<Path>>(&mut self, other: T) {
        self.root.push(other);
    }

    /// Consumes this filesystem and returns the underlying `PathBuf`.
    ///
    /// Note that this is a relatively dangerous operation and should be used
    /// with great caution!.
    pub fn into_path_unlocked(self) -> PathBuf {
        self.root
    }

    /// Returns the underlying `Path`.
    ///
    /// Note that this is a relatively dangerous operation and should be used
    /// with great caution!.
    pub fn as_path_unlocked(&self) -> &Path {
        &self.root
    }

    /// Creates the directory pointed to by this filesystem.
    ///
    /// Handles errors where other Cargo processes are also attempting to
    /// concurrently create this directory.
    pub fn create_dir(&self) -> CargoResult<()> {
        paths::create_dir_all(&self.root)?;
        Ok(())
    }

    /// Returns an adaptor that can be used to print the path of this
    /// filesystem.
    pub fn display(&self) -> Display<'_> {
        self.root.display()
    }

    /// Opens exclusive access to a file, returning the locked version of a
    /// file.
    ///
    /// This function will create a file at `path` if it doesn't already exist
    /// (including intermediate directories), and then it will acquire an
    /// exclusive lock on `path`. If the process must block waiting for the
    /// lock, the `msg` is printed to `config`.
    ///
    /// The returned file can be accessed to look at the path and also has
    /// read/write access to the underlying file.
    pub fn open_rw<P>(&self, path: P, config: &Config, msg: &str) -> CargoResult<FileLock>
    where
        P: AsRef<Path>,
    {
        self.open(
            path.as_ref(),
            OpenOptions::new().read(true).write(true).create(true),
            State::Exclusive,
            config,
            msg,
        )
    }

    /// Opens shared access to a file, returning the locked version of a file.
    ///
    /// This function will fail if `path` doesn't already exist, but if it does
    /// then it will acquire a shared lock on `path`. If the process must block
    /// waiting for the lock, the `msg` is printed to `config`.
    ///
    /// The returned file can be accessed to look at the path and also has read
    /// access to the underlying file. Any writes to the file will return an
    /// error.
    pub fn open_ro<P>(&self, path: P, config: &Config, msg: &str) -> CargoResult<FileLock>
    where
        P: AsRef<Path>,
    {
        self.open(
            path.as_ref(),
            OpenOptions::new().read(true),
            State::Shared,
            config,
            msg,
        )
    }

    fn open(
        &self,
        path: &Path,
        opts: &OpenOptions,
        state: State,
        config: &Config,
        msg: &str,
    ) -> CargoResult<FileLock> {
        let path = self.root.join(path);

        // If we want an exclusive lock then if we fail because of NotFound it's
        // likely because an intermediate directory didn't exist, so try to
        // create the directory and then continue.
        let f = opts
            .open(&path)
            .or_else(|e| {
                if e.kind() == io::ErrorKind::NotFound && state == State::Exclusive {
                    paths::create_dir_all(path.parent().unwrap())?;
                    Ok(opts.open(&path)?)
                } else {
                    Err(failure::Error::from(e))
                }
            })
            .chain_err(|| format!("failed to open: {}", path.display()))?;
        match state {
            State::Exclusive => {
                acquire(config, msg, &path, &|| f.try_lock_exclusive(), &|| {
                    f.lock_exclusive()
                })?;
            }
            State::Shared => {
                acquire(config, msg, &path, &|| f.try_lock_shared(), &|| {
                    f.lock_shared()
                })?;
            }
            State::Unlocked => {}
        }
        Ok(FileLock {
            f: Some(f),
            path,
            state,
        })
    }
}

impl PartialEq<Path> for Filesystem {
    fn eq(&self, other: &Path) -> bool {
        self.root == other
    }
}

impl PartialEq<Filesystem> for Path {
    fn eq(&self, other: &Filesystem) -> bool {
        self == other.root
    }
}

/// Acquires a lock on a file in a "nice" manner.
///
/// Almost all long-running blocking actions in Cargo have a status message
/// associated with them as we're not sure how long they'll take. Whenever a
/// conflicted file lock happens, this is the case (we're not sure when the lock
/// will be released).
///
/// This function will acquire the lock on a `path`, printing out a nice message
/// to the console if we have to wait for it. It will first attempt to use `try`
/// to acquire a lock on the crate, and in the case of contention it will emit a
/// status message based on `msg` to `config`'s shell, and then use `block` to
/// block waiting to acquire a lock.
///
/// Returns an error if the lock could not be acquired or if any error other
/// than a contention error happens.
fn acquire(
    config: &Config,
    msg: &str,
    path: &Path,
    r#try: &dyn Fn() -> io::Result<()>,
    block: &dyn Fn() -> io::Result<()>,
) -> CargoResult<()> {
    // File locking on Unix is currently implemented via `flock`, which is known
    // to be broken on NFS. We could in theory just ignore errors that happen on
    // NFS, but apparently the failure mode [1] for `flock` on NFS is **blocking
    // forever**, even if the "non-blocking" flag is passed!
    //
    // As a result, we just skip all file locks entirely on NFS mounts. That
    // should avoid calling any `flock` functions at all, and it wouldn't work
    // there anyway.
    //
    // [1]: https://github.com/rust-lang/cargo/issues/2615
    if is_on_nfs_mount(path) {
        return Ok(());
    }

    match r#try() {
        Ok(()) => return Ok(()),

        // In addition to ignoring NFS which is commonly not working we also
        // just ignore locking on filesystems that look like they don't
        // implement file locking. We detect that here via the return value of
        // locking (e.g., inspecting errno).
        #[cfg(unix)]
        Err(ref e) if e.raw_os_error() == Some(libc::ENOTSUP) => return Ok(()),

        #[cfg(target_os = "linux")]
        Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => return Ok(()),

        #[cfg(windows)]
        Err(ref e) if e.raw_os_error() == Some(ERROR_INVALID_FUNCTION as i32) => return Ok(()),

        Err(e) => {
            if e.raw_os_error() != lock_contended_error().raw_os_error() {
                let e = failure::Error::from(e);
                let cx = format!("failed to lock file: {}", path.display());
                return Err(e.context(cx).into());
            }
        }
    }
    let msg = format!("waiting for file lock on {}", msg);
    config.shell().status_with_color("Blocking", &msg, Cyan)?;

    block().chain_err(|| format!("failed to lock file: {}", path.display()))?;
    return Ok(());

    #[cfg(all(target_os = "linux", not(target_env = "musl")))]
    fn is_on_nfs_mount(path: &Path) -> bool {
        use std::ffi::CString;
        use std::mem;
        use std::os::unix::prelude::*;

        let path = match CString::new(path.as_os_str().as_bytes()) {
            Ok(path) => path,
            Err(_) => return false,
        };

        unsafe {
            let mut buf: libc::statfs = mem::zeroed();
            let r = libc::statfs(path.as_ptr(), &mut buf);

            r == 0 && buf.f_type as u32 == libc::NFS_SUPER_MAGIC as u32
        }
    }

    #[cfg(any(not(target_os = "linux"), target_env = "musl"))]
    fn is_on_nfs_mount(_path: &Path) -> bool {
        false
    }
}
<|endoftext|>


<commit_before>#![crate_id = "seax-svm"]
#![crate_type="lib"]

//! Contains the Seax Virtual Machine (SVM) and miscellaneous
//! support code.

#![feature(box_syntax)]
#![allow(dead_code)]

pub mod svm {

    use svm::slist::List;
    use svm::slist::Stack;

    /// Singly-linked list and stack implementations.
    mod slist {

        use svm::slist::List::{Cons,Nil};
        use std::fmt::Show;

        /// A stack implementation wrapping a List<T>
        pub struct Stack<T> {
            /// The head item of the list.
            head: Box<List<T>>
        }

        impl<T> Stack<T> {
            /// Push an item to the top of the stack, returning a new stack
            fn push(self, it: T) -> Stack<T> {
                Stack { head: Box::new(self.head.prepend(it)) }
            }

            /// Peak at the top item of the stack.
            ///
            /// Returns Some<T> if there is an item on top of the stack,
            /// and None if the stack is empty.
            fn peek(&self) -> Option<&T> {
                match *self.head {
                    Nil => None,
                    Cons(ref it,_) => Some(it)
                }
            }

            /// Returns an empty stack.
            fn empty() -> Stack<T> {
                Stack { head: box Nil }
            }

            /// Wraps a list into a stack.
            fn new(l: List<T>) -> Stack<T> {
                Stack { head: box l }
            }
        }

        /// Singly-linked cons list.
        ///
        /// This is used internally to represent list primitives in the machine.
        pub enum List<T> {
            Cons(T, Box<List<T>>),
            Nil,
        }

        /// Public implementation for List.
        impl<T> List<T> {

            /// Creates a new empty list
            pub fn new() -> List<T> {
                Nil
            }

            /// Prepends the given item to the list
            pub fn prepend(self, it: T) -> List<T> {
                Cons(it, box self)
            }

            /// Returns the length of the list
            pub fn length (&self) -> i32 {
                match *self {
                    Cons(_, ref tail) => 1 + tail.length(),
                    Nil => 0
                }
            }
        }

        impl<T> List<T> where T: Show {
            /// Return a string representation of the list
            fn to_string(&self) -> String {
                match *self {
                    Cons(ref head, ref tail) => format!("({:?}, {})", head, tail.to_string()),
                    Nil => format!("nil")
                }
            }

        }

       macro_rules! list(
            ( $e:expr, $($rest:expr),+ ) => ( Cons($e, Box::new(list!( $( $rest ),+ )) ));
            ( $e:expr ) => ( Cons($e, Box::new(Nil)) );
            () => ( @Empty )
        );

        #[cfg(test)]
        mod tests {
            use super::{List, Stack};
            use super::List::{Cons,Nil};

            #[test]
            fn test_list_length() {
                let l: List<i32> = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
                assert_eq!(l.length(), 3);
            }

            #[test]
            fn test_list_to_string() {
                let l: List<i32> = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
                assert_eq!(l.to_string(), "(1i32, (2i32, (3i32, nil)))");
            }

            #[test]
            fn test_stack_peek() {
                let s: Stack<i32> = Stack::new(Cons(1, Box::new(Cons(2, Box::new(Nil)))));
                assert_eq!(s.peek(), Some(&1));
            }

            #[test]
            fn test_stack_push() {
                let mut s: Stack<i32> = Stack::empty();
                assert_eq!(s.peek(), None);
                s = s.push(1);
                assert_eq!(s.peek(), Some(&1));
                s = s.push(6);
                assert_eq!(s.peek(), Some(&6));
            }

            #[test]
            fn test_stack_pop() {
                let mut s: Stack<i32> = Stack::empty();
                assert_eq!(s.peek(), None);
                s = s.push(1);
                assert_eq!(s.peek(), Some(&1));
                s = s.push(6);
                assert_eq!(s.peek(), Some(&6));
            }

            #[test]
            fn test_list_macro() {
                let l: List<i32> = list!(1i32, 2i32, 3i32);
                assert_eq!(l.to_string(), "(1i32, (2i32, (3i32, nil)))")
            }
        }
    }

    /// SVM item types
    enum Exp {
        Number(i32)
    }

    /// Represents a SVM machine state
    struct State {
        stack: Stack<Exp>,
        env: Stack<Exp>,
        control: Stack<Exp>,
        dump: Stack<Exp>
    }
}
<commit_msg>Make API functions public (whoops)<commit_after>#![crate_id = "seax-svm"]
#![crate_type="lib"]

//! Contains the Seax Virtual Machine (SVM) and miscellaneous
//! support code.

#![feature(box_syntax)]
#![allow(dead_code)]

pub mod svm {

    use svm::slist::List;
    use svm::slist::Stack;

    /// Singly-linked list and stack implementations.
    pub mod slist {

        use svm::slist::List::{Cons,Nil};
        use std::fmt::Show;

        /// A stack implementation wrapping a List<T>
        pub struct Stack<T> {
            /// The head item of the list.
            head: Box<List<T>>
        }

        impl<T> Stack<T> {
            /// Push an item to the top of the stack, returning a new stack
            pub fn push(self, it: T) -> Stack<T> {
                Stack { head: Box::new(self.head.prepend(it)) }
            }

            /// Peak at the top item of the stack.
            ///
            /// Returns Some<T> if there is an item on top of the stack,
            /// and None if the stack is empty.
            pub fn peek(&self) -> Option<&T> {
                match *self.head {
                    Nil => None,
                    Cons(ref it,_) => Some(it)
                }
            }

            /// Returns an empty stack.
            pub fn empty() -> Stack<T> {
                Stack { head: box Nil }
            }

            /// Wraps a list into a stack.
            pub fn new(l: List<T>) -> Stack<T> {
                Stack { head: box l }
            }
        }

        /// Singly-linked cons list.
        ///
        /// This is used internally to represent list primitives in the machine.
        pub enum List<T> {
            Cons(T, Box<List<T>>),
            Nil,
        }

        /// Public implementation for List.
        impl<T> List<T> {

            /// Creates a new empty list
            pub fn new() -> List<T> {
                Nil
            }

            /// Prepends the given item to the list
            pub fn prepend(self, it: T) -> List<T> {
                Cons(it, box self)
            }

            /// Returns the length of the list
            pub fn length (&self) -> i32 {
                match *self {
                    Cons(_, ref tail) => 1 + tail.length(),
                    Nil => 0
                }
            }
        }

        impl<T> List<T> where T: Show {
            /// Return a string representation of the list
            fn to_string(&self) -> String {
                match *self {
                    Cons(ref head, ref tail) => format!("({:?}, {})", head, tail.to_string()),
                    Nil => format!("nil")
                }
            }

        }

       macro_rules! list(
            ( $e:expr, $($rest:expr),+ ) => ( Cons($e, Box::new(list!( $( $rest ),+ )) ));
            ( $e:expr ) => ( Cons($e, Box::new(Nil)) );
            () => ( @Empty )
        );

        #[cfg(test)]
        mod tests {
            use super::{List, Stack};
            use super::List::{Cons,Nil};

            #[test]
            fn test_list_length() {
                let l: List<i32> = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
                assert_eq!(l.length(), 3);
            }

            #[test]
            fn test_list_to_string() {
                let l: List<i32> = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
                assert_eq!(l.to_string(), "(1i32, (2i32, (3i32, nil)))");
            }

            #[test]
            fn test_stack_peek() {
                let s: Stack<i32> = Stack::new(Cons(1, Box::new(Cons(2, Box::new(Nil)))));
                assert_eq!(s.peek(), Some(&1));
            }

            #[test]
            fn test_stack_push() {
                let mut s: Stack<i32> = Stack::empty();
                assert_eq!(s.peek(), None);
                s = s.push(1);
                assert_eq!(s.peek(), Some(&1));
                s = s.push(6);
                assert_eq!(s.peek(), Some(&6));
            }

            #[test]
            fn test_stack_pop() {
                let mut s: Stack<i32> = Stack::empty();
                assert_eq!(s.peek(), None);
                s = s.push(1);
                assert_eq!(s.peek(), Some(&1));
                s = s.push(6);
                assert_eq!(s.peek(), Some(&6));
            }

            #[test]
            fn test_list_macro() {
                let l: List<i32> = list!(1i32, 2i32, 3i32);
                assert_eq!(l.to_string(), "(1i32, (2i32, (3i32, nil)))")
            }
        }
    }

    /// SVM item types
    pub enum Exp {
        Number(i32)
    }

    /// Represents a SVM machine state
    pub struct State {
        stack: Stack<Exp>,
        env: Stack<Exp>,
        control: Stack<Exp>,
        dump: Stack<Exp>
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io;
use std::io::prelude::*;

type SudokuCandidate = u64;  // or u32
type SudokuCellGroups = HashMap<usize, Vec<Vec<usize>>>;

const SUDOKU_DIGIT_BASE: u32 = 10;
const SUDOKU_BOX_SIZE: usize = 3;
const SUDOKU_NO_CANDIDATES: SudokuCandidate = 0;
const SUDOKU_ALL_CANDIDATES: SudokuCandidate = ((1 << SUDOKU_CANDIDATE_SIZE) - 1);

const SUDOKU_GROUP_SIZE: usize = SUDOKU_BOX_SIZE * SUDOKU_BOX_SIZE;
const SUDOKU_CANDIDATE_SIZE: usize = SUDOKU_GROUP_SIZE;
const SUDOKU_CELL_SIZE: usize = SUDOKU_GROUP_SIZE * SUDOKU_GROUP_SIZE;

// Sudoku cell that contains candidates as a bitboard
#[derive(Clone, Copy)]
struct SudokuCell {
    candidates: SudokuCandidate
}

impl SudokuCell {
    fn new() -> SudokuCell {
        SudokuCell { candidates: SUDOKU_NO_CANDIDATES }
    }

    fn to_string(&self) -> String {
        let mut line = String::new();
        for candidate in 0..(SUDOKU_CANDIDATE_SIZE as SudokuCandidate) {
            if self.has_candidate(&candidate) {
                line.push_str(&(candidate+1).to_string());
            }
        }
        line
    }

    fn preset_full_candidate(&mut self) {
        self.candidates = SUDOKU_ALL_CANDIDATES;
    }

    // Input '1'..'9'
    fn preset_candidate(&mut self, ch: char) {
        let code_digit_base = '1'.to_digit(SUDOKU_DIGIT_BASE).unwrap();
        match ch {
            '1'...'9' => {
                let number = (ch.to_digit(SUDOKU_DIGIT_BASE).unwrap() - code_digit_base) as SudokuCandidate;
                self.candidates = self.digit_to_candidate(&number);
            }
            _ => {}
        }
    }

    // Input 0..8
    fn overwrite_candidate(&mut self, candidate: SudokuCandidate) {
        if self.count_candidates() > 1 {
            self.candidates = self.digit_to_candidate(&candidate);
        }
    }

    fn count_candidates(&self) -> usize {
        (self.candidates & SUDOKU_ALL_CANDIDATES).count_ones() as usize
    }

    fn has_unique_candidate(&self) -> bool {
        SudokuCell::is_unique_candidate(self.candidates)
    }

    fn is_unique_candidate(candidates: SudokuCandidate) -> bool {
        // Check whether only one bit is set
        candidates > 0 && (candidates & (candidates - 1)) == 0
    }

    fn has_all_candidates(&self) -> bool {
        self.candidates == SUDOKU_ALL_CANDIDATES
    }

    // Input 0..8
    fn can_mask(&mut self, candidates: SudokuCandidate) -> bool {
        (self.candidates & self.digit_to_candidate(&candidates)) != 0
    }

    fn merge_candidate(&mut self, rhs: &SudokuCell) {
        self.candidates |= rhs.candidates;
    }

    // Returns whether no candidates are merged
    fn merge_unique_candidate(&mut self, rhs: &SudokuCell) -> bool {
        if rhs.has_unique_candidate() {
            if (self.candidates & rhs.candidates) != 0 {
                return true;
            }
            self.candidates |= rhs.candidates;
        }
        false
    }

    fn filter_by_candidates(&mut self, rhs: &SudokuCell) {
        if !self.has_unique_candidate() {
            self.candidates &= !rhs.candidates;
        }
    }

    fn fill_unused_candidate(&mut self, rhs: &SudokuCell) {
        if !self.has_unique_candidate() {
            let candidates = SUDOKU_ALL_CANDIDATES & !rhs.candidates;
            if SudokuCell::is_unique_candidate(candidates) {
                self.candidates = candidates;
            }
        }
    }

    // Input 0..8
    fn digit_to_candidate(&self, candidate: &SudokuCandidate) -> SudokuCandidate {
        (1 as SudokuCandidate) << candidate
    }

    // Input 0..8
    fn has_candidate(&self, candidate: &SudokuCandidate) -> bool {
        (self.candidates & self.digit_to_candidate(&candidate)) != 0
    }
}

// Generator for sudoku cellgroups
struct SudokuGroupGen {
    index: usize
}

impl SudokuGroupGen {
    fn new() -> SudokuGroupGen {
        SudokuGroupGen { index:0 }
    }

    fn next(&mut self) -> Option<Vec<usize>> {
        if self.index < SUDOKU_GROUP_SIZE {
            let lower = self.index * SUDOKU_GROUP_SIZE;
            let upper = (self.index + 1) * SUDOKU_GROUP_SIZE;
            self.index += 1;
            Some((lower..upper).collect::<Vec<_>>())
        } else if self.index < (SUDOKU_GROUP_SIZE * 2) {
            let column = self.index - SUDOKU_GROUP_SIZE;
            self.index += 1;
            Some((0..SUDOKU_GROUP_SIZE).map(
                |row| column + row * SUDOKU_GROUP_SIZE).collect::<Vec<_>>())
        } else if self.index < (SUDOKU_GROUP_SIZE * 3) {
            let box_index = self.index - SUDOKU_GROUP_SIZE * 2;
            let offset = (box_index % 3) * 3  + (box_index / 3) * SUDOKU_GROUP_SIZE * 3;
            let mut indexes : Vec<usize> = Vec::new();
            for row in 0..SUDOKU_BOX_SIZE {
                let x = (0..SUDOKU_BOX_SIZE).map(
                    |column| row * SUDOKU_GROUP_SIZE + column + offset).collect::<Vec<_>>();
                indexes.extend(x);
            }
            self.index += 1;
            Some(indexes)
        } else {
            None
        }
    }
}

// Sudoku cell map
struct SudokuMap<'a> {
    cells : Vec<SudokuCell>,
    groups : &'a SudokuCellGroups,
}

impl<'a> SudokuMap<'a> {
    fn new(line: &str, cell_groups: &'a SudokuCellGroups) -> SudokuMap<'a> {
        let mut cells = vec![SudokuCell::new(); SUDOKU_CELL_SIZE];
        for cell in &mut cells {
            cell.preset_full_candidate();
        }

        // Leave tail cells if the line is shorter than the number of cells.
        for (index, ch) in line.chars().enumerate() {
            cells[index].preset_candidate(ch);
        };
        SudokuMap { cells:cells, groups: cell_groups }
    }

    fn to_string(&self, one_line: bool) -> String {
        let mut full_text = String::new();

        for row in 0..SUDOKU_GROUP_SIZE {
            let mut line = String::new();
            for column in 0..SUDOKU_GROUP_SIZE {
                let index = row * SUDOKU_GROUP_SIZE + column;
                let cell_str = self.cells[index].to_string();
                line.push_str(&cell_str);
                if !one_line {
                    line.push_str(":");
                }
            }
            if !one_line {
                line.push_str("\n");
            }
            full_text.push_str(&line);
        }
        full_text
    }

    fn solve(&mut self) -> bool {
        let mut prev_count = SUDOKU_CELL_SIZE * SUDOKU_CANDIDATE_SIZE;
        loop {
            self.filter_unique_candidates();
            self.find_unused_candidates();

            if self.is_solved() {
                return true;
            }

            if !self.is_consistent() {
                return false;
            }

            let count = (0..SUDOKU_CELL_SIZE).fold(
                0, |sum, index| sum + self.cells[index].count_candidates());
            if prev_count == count {
                break;
            }
            prev_count = count;
        }

        let index_min_count = self.find_backtracking_target();
        if self.cells[index_min_count].count_candidates() <= 1 {
            return false;
        }

        for candidate in 0..(SUDOKU_CANDIDATE_SIZE as SudokuCandidate) {
            if self.cells[index_min_count].can_mask(candidate) {
                let mut new_map = SudokuMap::new("", self.groups);
                new_map.cells = self.cells.clone();
                new_map.cells[index_min_count].overwrite_candidate(candidate);
                if new_map.solve() {
                    self.cells = new_map.cells;
                    return self.is_solved();
                }
            }
        }

        false
    }

    fn filter_unique_candidates(&mut self) {
        for target_index in 0..SUDOKU_CELL_SIZE {
            if self.cells[target_index].has_unique_candidate() {
                continue;
            }

            let mut sum = SudokuCell::new();
            for group in self.groups[&target_index].iter() {
                for cell_index in group.iter() {
                    if *cell_index != target_index {
                        sum.merge_unique_candidate(&self.cells[*cell_index]);
                    }
                }
            }
            self.cells[target_index].filter_by_candidates(&sum);
        }
    }

    fn find_unused_candidates(&mut self) {
        for target_index in 0..SUDOKU_CELL_SIZE {
            if self.cells[target_index].has_unique_candidate() {
                continue;
            }

            for group in self.groups[&target_index].iter() {
                let mut sum = SudokuCell::new();
                for cell_index in group.iter() {
                    if *cell_index != target_index {
                        sum.merge_candidate(&self.cells[*cell_index]);
                    }
                }
                self.cells[target_index].fill_unused_candidate(&sum);
            }
        }
    }

    fn find_backtracking_target(&self) -> usize {
        // SUDOKU_CELL_SIZE = a large enough number
        let mut min_count = SUDOKU_CELL_SIZE;
        let mut cell_counts = Vec::new();

        for row_index in 0..SUDOKU_GROUP_SIZE {
            let mut row_counts = vec![SUDOKU_CELL_SIZE; SUDOKU_GROUP_SIZE];
            for column_index in 0..SUDOKU_GROUP_SIZE {
                let cell_count = self.cells[row_index * SUDOKU_GROUP_SIZE + column_index].count_candidates();
                if cell_count > 1 {
                    row_counts[column_index] = cell_count;
                    if cell_count < min_count {
                        min_count = cell_count;
                    }
                }
            }
            cell_counts.push(row_counts);
        }

        let row_counts = cell_counts.iter().map(
            |row| row.iter().fold(0, |sum, &count| sum + if count == min_count { 1 } else { 0 })).collect::<Vec<usize>>();
        let max_row_count = row_counts.iter().max().unwrap();
        let target_row = row_counts.iter().position(|&count| count == *max_row_count).unwrap();
        let target_column = cell_counts[target_row].iter().position(|&count| count == min_count).unwrap();
        target_row * SUDOKU_GROUP_SIZE + target_column
    }

    fn is_solved(&self) -> bool {
        let mut group_gen = SudokuGroupGen::new();
        while let Some(indexes) = group_gen.next() {
            if !self.is_group_solved(indexes) {
                return false;
            }
        }
        true
    }

    fn is_group_solved(&self, cell_indexes: Vec<usize>) -> bool {
        let mut sum = SudokuCell::new();
        let mut conflict = false;
        for cell_index in cell_indexes {
            let cell = &self.cells[cell_index];
            conflict |= sum.merge_unique_candidate(&cell);
        }
        sum.has_all_candidates() && !conflict
    }

    fn is_consistent(&self) -> bool {
        let mut group_gen = SudokuGroupGen::new();
        while let Some(indexes) = group_gen.next() {
            if !self.is_group_consistent(indexes) {
                return false;
            }
        }
        true
    }

    fn is_group_consistent(&self, cell_indexes: Vec<usize>) -> bool {
        let mut all_candidates = SudokuCell::new();
        let mut unique_candidates = SudokuCell::new();
        let mut conflict = false;

        for cell_index in cell_indexes {
            all_candidates.merge_candidate(&self.cells[cell_index]);
            conflict |= unique_candidates.merge_unique_candidate(&self.cells[cell_index]);
        }
        all_candidates.has_all_candidates() && !conflict
    }
}

// Set of sudoku cellgroups
fn create_group_index_set() -> SudokuCellGroups {
    let mut groups = HashMap::new();
    for cell_index in 0..SUDOKU_CELL_SIZE {
        let mut group_candidates = Vec::new();
        let row_number = cell_index / SUDOKU_GROUP_SIZE;
        let row_lower = row_number * SUDOKU_GROUP_SIZE;
        let row_upper = (row_number + 1) * SUDOKU_GROUP_SIZE;
        let row = (row_lower..row_upper).collect::<Vec<_>>();
        group_candidates.push(row);

        let column_number = cell_index % SUDOKU_GROUP_SIZE;
        let column = (0..SUDOKU_GROUP_SIZE).map(|i| column_number + i * SUDOKU_GROUP_SIZE).collect::<Vec<_>>();
        group_candidates.push(column);

        let box_offset = (row_number / SUDOKU_BOX_SIZE) * SUDOKU_BOX_SIZE * SUDOKU_GROUP_SIZE +
            (column_number / SUDOKU_BOX_SIZE) * SUDOKU_BOX_SIZE;
        let mut cell_box = Vec::new();
        for row_offset in 0..SUDOKU_BOX_SIZE {
            let x = (0..SUDOKU_BOX_SIZE).map(|column_offset| row_offset * SUDOKU_GROUP_SIZE + column_offset + box_offset);
            cell_box.extend(x);
        }
        group_candidates.push(cell_box);
        groups.insert(cell_index, group_candidates);
    }
    groups
}

fn main() {
    // Shares cell groups between all questions
    let cell_groups = create_group_index_set();
    println!("Solving in Rust");

    let stdin = io::stdin();
    let mut lines = Vec::new();
    let mut count = 0;
    for line in stdin.lock().lines() {
        let line = line.unwrap();
        lines.push(line);
        count += 1;
    }

    let mut result = true;
    let mut answers = String::new();
    for line in lines {
        let mut sudoku_map = SudokuMap::new(&line, &cell_groups);
        result &= sudoku_map.solve();
        let s = sudoku_map.to_string(true);
        answers.push_str(&s);
        answers.push_str("\n");
    }

    print!("{}", answers);
    if result {
        println!("All {} cases passed.", count);
    }
}
<commit_msg>Stop early in cell consistency checking<commit_after>use std::collections::HashMap;
use std::io;
use std::io::prelude::*;

type SudokuCandidate = u64;  // or u32
type SudokuCellGroups = HashMap<usize, Vec<Vec<usize>>>;

const SUDOKU_DIGIT_BASE: u32 = 10;
const SUDOKU_BOX_SIZE: usize = 3;
const SUDOKU_NO_CANDIDATES: SudokuCandidate = 0;
const SUDOKU_ALL_CANDIDATES: SudokuCandidate = ((1 << SUDOKU_CANDIDATE_SIZE) - 1);

const SUDOKU_GROUP_SIZE: usize = SUDOKU_BOX_SIZE * SUDOKU_BOX_SIZE;
const SUDOKU_CANDIDATE_SIZE: usize = SUDOKU_GROUP_SIZE;
const SUDOKU_CELL_SIZE: usize = SUDOKU_GROUP_SIZE * SUDOKU_GROUP_SIZE;

// Sudoku cell that contains candidates as a bitboard
#[derive(Clone, Copy)]
struct SudokuCell {
    candidates: SudokuCandidate
}

impl SudokuCell {
    fn new() -> SudokuCell {
        SudokuCell { candidates: SUDOKU_NO_CANDIDATES }
    }

    fn to_string(&self) -> String {
        let mut line = String::new();
        for candidate in 0..(SUDOKU_CANDIDATE_SIZE as SudokuCandidate) {
            if self.has_candidate(&candidate) {
                line.push_str(&(candidate+1).to_string());
            }
        }
        line
    }

    fn preset_full_candidate(&mut self) {
        self.candidates = SUDOKU_ALL_CANDIDATES;
    }

    // Input '1'..'9'
    fn preset_candidate(&mut self, ch: char) {
        let code_digit_base = '1'.to_digit(SUDOKU_DIGIT_BASE).unwrap();
        match ch {
            '1'...'9' => {
                let number = (ch.to_digit(SUDOKU_DIGIT_BASE).unwrap() - code_digit_base) as SudokuCandidate;
                self.candidates = self.digit_to_candidate(&number);
            }
            _ => {}
        }
    }

    // Input 0..8
    fn overwrite_candidate(&mut self, candidate: SudokuCandidate) {
        if self.count_candidates() > 1 {
            self.candidates = self.digit_to_candidate(&candidate);
        }
    }

    fn count_candidates(&self) -> usize {
        (self.candidates & SUDOKU_ALL_CANDIDATES).count_ones() as usize
    }

    fn has_unique_candidate(&self) -> bool {
        SudokuCell::is_unique_candidate(self.candidates)
    }

    fn is_unique_candidate(candidates: SudokuCandidate) -> bool {
        // Check whether only one bit is set
        candidates > 0 && (candidates & (candidates - 1)) == 0
    }

    fn has_all_candidates(&self) -> bool {
        self.candidates == SUDOKU_ALL_CANDIDATES
    }

    // Input 0..8
    fn can_mask(&mut self, candidates: SudokuCandidate) -> bool {
        (self.candidates & self.digit_to_candidate(&candidates)) != 0
    }

    fn merge_candidate(&mut self, rhs: &SudokuCell) {
        self.candidates |= rhs.candidates;
    }

    // Returns whether no candidates are merged
    fn merge_unique_candidate(&mut self, rhs: &SudokuCell) -> bool {
        if rhs.has_unique_candidate() {
            if (self.candidates & rhs.candidates) != 0 {
                return true;
            }
            self.candidates |= rhs.candidates;
        }
        false
    }

    fn filter_by_candidates(&mut self, rhs: &SudokuCell) {
        if !self.has_unique_candidate() {
            self.candidates &= !rhs.candidates;
        }
    }

    fn fill_unused_candidate(&mut self, rhs: &SudokuCell) {
        if !self.has_unique_candidate() {
            let candidates = SUDOKU_ALL_CANDIDATES & !rhs.candidates;
            if SudokuCell::is_unique_candidate(candidates) {
                self.candidates = candidates;
            }
        }
    }

    // Input 0..8
    fn digit_to_candidate(&self, candidate: &SudokuCandidate) -> SudokuCandidate {
        (1 as SudokuCandidate) << candidate
    }

    // Input 0..8
    fn has_candidate(&self, candidate: &SudokuCandidate) -> bool {
        (self.candidates & self.digit_to_candidate(&candidate)) != 0
    }
}

// Generator for sudoku cellgroups
struct SudokuGroupGen {
    index: usize
}

impl SudokuGroupGen {
    fn new() -> SudokuGroupGen {
        SudokuGroupGen { index:0 }
    }

    fn next(&mut self) -> Option<Vec<usize>> {
        if self.index < SUDOKU_GROUP_SIZE {
            let lower = self.index * SUDOKU_GROUP_SIZE;
            let upper = (self.index + 1) * SUDOKU_GROUP_SIZE;
            self.index += 1;
            Some((lower..upper).collect::<Vec<_>>())
        } else if self.index < (SUDOKU_GROUP_SIZE * 2) {
            let column = self.index - SUDOKU_GROUP_SIZE;
            self.index += 1;
            Some((0..SUDOKU_GROUP_SIZE).map(
                |row| column + row * SUDOKU_GROUP_SIZE).collect::<Vec<_>>())
        } else if self.index < (SUDOKU_GROUP_SIZE * 3) {
            let box_index = self.index - SUDOKU_GROUP_SIZE * 2;
            let offset = (box_index % 3) * 3  + (box_index / 3) * SUDOKU_GROUP_SIZE * 3;
            let mut indexes : Vec<usize> = Vec::new();
            for row in 0..SUDOKU_BOX_SIZE {
                let x = (0..SUDOKU_BOX_SIZE).map(
                    |column| row * SUDOKU_GROUP_SIZE + column + offset).collect::<Vec<_>>();
                indexes.extend(x);
            }
            self.index += 1;
            Some(indexes)
        } else {
            None
        }
    }
}

// Sudoku cell map
struct SudokuMap<'a> {
    cells : Vec<SudokuCell>,
    groups : &'a SudokuCellGroups,
}

impl<'a> SudokuMap<'a> {
    fn new(line: &str, cell_groups: &'a SudokuCellGroups) -> SudokuMap<'a> {
        let mut cells = vec![SudokuCell::new(); SUDOKU_CELL_SIZE];
        for cell in &mut cells {
            cell.preset_full_candidate();
        }

        // Leave tail cells if the line is shorter than the number of cells.
        for (index, ch) in line.chars().enumerate() {
            cells[index].preset_candidate(ch);
        };
        SudokuMap { cells:cells, groups: cell_groups }
    }

    fn to_string(&self, one_line: bool) -> String {
        let mut full_text = String::new();

        for row in 0..SUDOKU_GROUP_SIZE {
            let mut line = String::new();
            for column in 0..SUDOKU_GROUP_SIZE {
                let index = row * SUDOKU_GROUP_SIZE + column;
                let cell_str = self.cells[index].to_string();
                line.push_str(&cell_str);
                if !one_line {
                    line.push_str(":");
                }
            }
            if !one_line {
                line.push_str("\n");
            }
            full_text.push_str(&line);
        }
        full_text
    }

    fn solve(&mut self) -> bool {
        let mut prev_count = SUDOKU_CELL_SIZE * SUDOKU_CANDIDATE_SIZE;
        loop {
            self.filter_unique_candidates();
            self.find_unused_candidates();

            if self.is_solved() {
                return true;
            }

            if !self.is_consistent() {
                return false;
            }

            let count = (0..SUDOKU_CELL_SIZE).fold(
                0, |sum, index| sum + self.cells[index].count_candidates());
            if prev_count == count {
                break;
            }
            prev_count = count;
        }

        let index_min_count = self.find_backtracking_target();
        if self.cells[index_min_count].count_candidates() <= 1 {
            return false;
        }

        for candidate in 0..(SUDOKU_CANDIDATE_SIZE as SudokuCandidate) {
            if self.cells[index_min_count].can_mask(candidate) {
                let mut new_map = SudokuMap::new("", self.groups);
                new_map.cells = self.cells.clone();
                new_map.cells[index_min_count].overwrite_candidate(candidate);
                if new_map.solve() {
                    self.cells = new_map.cells;
                    return self.is_solved();
                }
            }
        }

        false
    }

    fn filter_unique_candidates(&mut self) {
        for target_index in 0..SUDOKU_CELL_SIZE {
            if self.cells[target_index].has_unique_candidate() {
                continue;
            }

            let mut sum = SudokuCell::new();
            for group in self.groups[&target_index].iter() {
                for cell_index in group.iter() {
                    if *cell_index != target_index {
                        sum.merge_unique_candidate(&self.cells[*cell_index]);
                    }
                }
            }
            self.cells[target_index].filter_by_candidates(&sum);
        }
    }

    fn find_unused_candidates(&mut self) {
        for target_index in 0..SUDOKU_CELL_SIZE {
            if self.cells[target_index].has_unique_candidate() {
                continue;
            }

            for group in self.groups[&target_index].iter() {
                let mut sum = SudokuCell::new();
                for cell_index in group.iter() {
                    if *cell_index != target_index {
                        sum.merge_candidate(&self.cells[*cell_index]);
                    }
                }
                self.cells[target_index].fill_unused_candidate(&sum);
            }
        }
    }

    fn find_backtracking_target(&self) -> usize {
        // SUDOKU_CELL_SIZE = a large enough number
        let mut min_count = SUDOKU_CELL_SIZE;
        let mut cell_counts = Vec::new();

        for row_index in 0..SUDOKU_GROUP_SIZE {
            let mut row_counts = vec![SUDOKU_CELL_SIZE; SUDOKU_GROUP_SIZE];
            for column_index in 0..SUDOKU_GROUP_SIZE {
                let cell_count = self.cells[row_index * SUDOKU_GROUP_SIZE + column_index].count_candidates();
                if cell_count > 1 {
                    row_counts[column_index] = cell_count;
                    if cell_count < min_count {
                        min_count = cell_count;
                    }
                }
            }
            cell_counts.push(row_counts);
        }

        let row_counts = cell_counts.iter().map(
            |row| row.iter().fold(
                0, |sum, &count| sum + if count == min_count { 1 } else { 0 })).
            collect::<Vec<usize>>();

        let max_row_count = row_counts.iter().max().unwrap();
        let target_row = row_counts.iter().position(|&count| count == *max_row_count).unwrap();
        let target_column = cell_counts[target_row].iter().position(
            |&count| count == min_count).unwrap();

        target_row * SUDOKU_GROUP_SIZE + target_column
    }

    fn is_solved(&self) -> bool {
        for cell_index in 0..SUDOKU_CELL_SIZE {
            if !self.cells[cell_index].has_unique_candidate() {
                return false;
            }
        }

        let mut group_gen = SudokuGroupGen::new();
        while let Some(indexes) = group_gen.next() {
            if !self.is_group_solved(indexes) {
                return false;
            }
        }
        true
    }

    fn is_group_solved(&self, cell_indexes: Vec<usize>) -> bool {
        let mut sum = SudokuCell::new();
        let mut conflict = false;
        for cell_index in cell_indexes {
            let cell = &self.cells[cell_index];
            conflict |= sum.merge_unique_candidate(&cell);
        }
        sum.has_all_candidates() && !conflict
    }

    fn is_consistent(&self) -> bool {
        let mut group_gen = SudokuGroupGen::new();
        while let Some(indexes) = group_gen.next() {
            if !self.is_group_consistent(indexes) {
                return false;
            }
        }
        true
    }

    fn is_group_consistent(&self, cell_indexes: Vec<usize>) -> bool {
        let mut all_candidates = SudokuCell::new();
        let mut unique_candidates = SudokuCell::new();
        let mut conflict = false;

        for cell_index in cell_indexes {
            all_candidates.merge_candidate(&self.cells[cell_index]);
            conflict |= unique_candidates.merge_unique_candidate(&self.cells[cell_index]);
            if conflict {
                return false;
            }
        }
        all_candidates.has_all_candidates() && !conflict
    }
}

// Set of sudoku cellgroups
fn create_group_index_set() -> SudokuCellGroups {
    let mut groups = HashMap::new();
    for cell_index in 0..SUDOKU_CELL_SIZE {
        let mut group_candidates = Vec::new();
        let row_number = cell_index / SUDOKU_GROUP_SIZE;
        let row_lower = row_number * SUDOKU_GROUP_SIZE;
        let row_upper = (row_number + 1) * SUDOKU_GROUP_SIZE;
        let row = (row_lower..row_upper).collect::<Vec<_>>();
        group_candidates.push(row);

        let column_number = cell_index % SUDOKU_GROUP_SIZE;
        let column = (0..SUDOKU_GROUP_SIZE).map(|i| column_number + i * SUDOKU_GROUP_SIZE).collect::<Vec<_>>();
        group_candidates.push(column);

        let box_offset = (row_number / SUDOKU_BOX_SIZE) * SUDOKU_BOX_SIZE * SUDOKU_GROUP_SIZE +
            (column_number / SUDOKU_BOX_SIZE) * SUDOKU_BOX_SIZE;
        let mut cell_box = Vec::new();
        for row_offset in 0..SUDOKU_BOX_SIZE {
            let x = (0..SUDOKU_BOX_SIZE).map(|column_offset| row_offset * SUDOKU_GROUP_SIZE + column_offset + box_offset);
            cell_box.extend(x);
        }
        group_candidates.push(cell_box);
        groups.insert(cell_index, group_candidates);
    }
    groups
}

fn main() {
    // Shares cell groups between all questions
    let cell_groups = create_group_index_set();
    println!("Solving in Rust");

    let stdin = io::stdin();
    let mut lines = Vec::new();
    let mut count = 0;
    for line in stdin.lock().lines() {
        let line = line.unwrap();
        lines.push(line);
        count += 1;
    }

    let mut result = true;
    let mut answers = String::new();
    for line in lines {
        let mut sudoku_map = SudokuMap::new(&line, &cell_groups);
        result &= sudoku_map.solve();
        let s = sudoku_map.to_string(true);
        answers.push_str(&s);
        answers.push_str("\n");
    }

    print!("{}", answers);
    if result {
        println!("All {} cases passed.", count);
    }
}
<|endoftext|>