<commit_before>use clap::{crate_version, value_t};

use std::env;
use std::ffi::OsStr;
use std::io;
use std::process::{self, Command, ExitStatus};
use std::sync::{Arc, Condvar, Mutex};
use std::thread;
use std::time::{Duration, Instant};

#[path = "../common.rs"]
mod common;

fn main() {
    if !common::archive_file_path().exists() {
        let version = common::afl_rustc_version();
        eprintln!(
            "AFL LLVM runtime is not built with Rust {}, run `cargo \
             install --force afl` to build it.",
            version
        );
        process::exit(1);
    }

    let app_matches = clap_app().get_matches();
    // This unwrap is okay because we set SubcommandRequiredElseHelp at the top level, and afl is
    // the only subcommand
    let afl_matches = app_matches.subcommand_matches("afl").unwrap();

    match afl_matches.subcommand() {
        ("analyze", Some(sub_matches)) => {
            let args = sub_matches
                .values_of_os("afl-analyze args")
                .unwrap_or_default();
            run_afl(args, "afl-analyze", None);
        }
        ("cmin", Some(sub_matches)) => {
            let args = sub_matches
                .values_of_os("afl-cmin args")
                .unwrap_or_default();
            run_afl(args, "afl-cmin", None);
        }
        ("fuzz", Some(sub_matches)) => {
            let args = sub_matches
                .values_of_os("afl-fuzz args")
                .unwrap_or_default();
            let timeout = sub_matches
                .value_of("max_total_time")
                .map(|_| value_t!(sub_matches, "max_total_time", u64).unwrap_or_else(|e| e.exit()));
            run_afl(args, "afl-fuzz", timeout);
        }
        ("gotcpu", Some(sub_matches)) => {
            let args = sub_matches
                .values_of_os("afl-gotcpu args")
                .unwrap_or_default();
            run_afl(args, "afl-gotcpu", None);
        }
        ("plot", Some(sub_matches)) => {
            let args = sub_matches
                .values_of_os("afl-plot args")
                .unwrap_or_default();
            run_afl(args, "afl-plot", None);
        }
        ("showmap", Some(sub_matches)) => {
            let args = sub_matches
                .values_of_os("afl-showmap args")
                .unwrap_or_default();
            run_afl(args, "afl-showmap", None);
        }
        ("tmin", Some(sub_matches)) => {
            let args = sub_matches
                .values_of_os("afl-tmin args")
                .unwrap_or_default();
            run_afl(args, "afl-tmin", None);
        }
        ("whatsup", Some(sub_matches)) => {
            let args = sub_matches
                .values_of_os("afl-whatsup args")
                .unwrap_or_default();
            run_afl(args, "afl-whatsup", None);
        }
        (subcommand, Some(sub_matches)) => {
            let args = sub_matches.values_of_os("").unwrap_or_default();
            run_cargo(subcommand, args);
        }
        // unreachable due to SubcommandRequiredElseHelp on "afl" subcommand
        (_, None) => unreachable!(),
    }
}

fn clap_app() -> clap::App<'static, 'static> {
    use clap::{
        App,
        AppSettings::{
            AllowExternalSubcommands, AllowLeadingHyphen, DisableHelpFlags, DisableHelpSubcommand,
            DisableVersion, SubcommandRequiredElseHelp,
        },
        Arg, SubCommand,
    };

    App::new("cargo afl")
        .bin_name("cargo")
        .setting(SubcommandRequiredElseHelp)
        .subcommand(
            SubCommand::with_name("afl")
                .version(crate_version!())
                .setting(SubcommandRequiredElseHelp)
                .setting(AllowExternalSubcommands)
                .usage("cargo afl [SUBCOMMAND or Cargo SUBCOMMAND]")
                .after_help(
                    "In addition to the subcommands above, Cargo subcommands are also \
                 supported (see `cargo help` for a list of all Cargo subcommands).",
                )
                .subcommand(
                    SubCommand::with_name("analyze")
                        .about("Invoke afl-analyze")
                        .setting(AllowLeadingHyphen)
                        .setting(DisableHelpSubcommand)
                        .setting(DisableHelpFlags)
                        .setting(DisableVersion)
                        .arg(Arg::with_name("afl-analyze args").multiple(true)),
                )
                .subcommand(
                    SubCommand::with_name("cmin")
                        .about("Invoke afl-cmin")
                        .setting(AllowLeadingHyphen)
                        .setting(DisableHelpSubcommand)
                        .setting(DisableHelpFlags)
                        .setting(DisableVersion)
                        .arg(Arg::with_name("afl-cmin args").multiple(true)),
                )
                .subcommand(
                    SubCommand::with_name("fuzz")
                        .about("Invoke afl-fuzz")
                        .setting(AllowLeadingHyphen)
                        .setting(DisableHelpSubcommand)
                        .setting(DisableHelpFlags)
                        .setting(DisableVersion)
                        .arg(
                            Arg::with_name("max_total_time")
                                .long("max_total_time")
                                .takes_value(true)
                                .help("Maximum amount of time to run the fuzzer"),
                        )
                        .arg(Arg::with_name("afl-fuzz args").multiple(true)),
                )
                .subcommand(
                    SubCommand::with_name("gotcpu")
                        .about("Invoke afl-gotcpu")
                        .setting(AllowLeadingHyphen)
                        .setting(DisableHelpSubcommand)
                        .setting(DisableHelpFlags)
                        .setting(DisableVersion)
                        .arg(Arg::with_name("afl-gotcpu args").multiple(true)),
                )
                .subcommand(
                    SubCommand::with_name("plot")
                        .about("Invoke afl-plot")
                        .setting(AllowLeadingHyphen)
                        .setting(DisableHelpSubcommand)
                        .setting(DisableHelpFlags)
                        .setting(DisableVersion)
                        .arg(Arg::with_name("afl-plot args").multiple(true)),
                )
                .subcommand(
                    SubCommand::with_name("showmap")
                        .about("Invoke afl-showmap")
                        .setting(AllowLeadingHyphen)
                        .setting(DisableHelpSubcommand)
                        .setting(DisableHelpFlags)
                        .setting(DisableVersion)
                        .arg(Arg::with_name("afl-showmap args").multiple(true)),
                )
                .subcommand(
                    SubCommand::with_name("tmin")
                        .about("Invoke afl-tmin")
                        .setting(AllowLeadingHyphen)
                        .setting(DisableHelpSubcommand)
                        .setting(DisableHelpFlags)
                        .setting(DisableVersion)
                        .arg(Arg::with_name("afl-tmin args").multiple(true)),
                )
                .subcommand(
                    SubCommand::with_name("whatsup")
                        .about("Invoke afl-whatsup")
                        .setting(AllowLeadingHyphen)
                        .setting(DisableHelpSubcommand)
                        .setting(DisableHelpFlags)
                        .setting(DisableVersion)
                        .arg(Arg::with_name("afl-whatsup args").multiple(true)),
                ),
        )
}

fn run_timeout_terminate(mut cmd: Command, timeout: Option<u64>) -> Result<ExitStatus, io::Error> {
    let timeout = match timeout {
        Some(timeout) => Duration::from_secs(timeout),
        None => return cmd.status(),
    };
    let start_time = Instant::now();

    let mut child = cmd.spawn()?;
    let pid = child.id();

    let pair = Arc::new((Mutex::new(false), Condvar::new()));
    let (stop_mutex, condvar) = &*pair;
    let thread_handle = {
        let pair = pair.clone();
        thread::spawn(move || -> Result<(), io::Error> {
            // This thread will wait until the child process has exited, or the
            // timeout has elapsed, whichever comes first. If the timeout
            // elapses, and the process is still running, it will send SIGTERM
            // to the child process.

            let (stop_mutex, condvar) = &*pair;
            let mut stop = stop_mutex.lock().unwrap();
            loop {
                let elapsed = Instant::now() - start_time;
                if elapsed >= timeout {
                    break;
                }

                let dur = timeout - elapsed;
                let results = condvar.wait_timeout(stop, dur).unwrap();
                stop = results.0;
                if *stop {
                    // Blocking waitid call on the main thread has returned,
                    // thus the child process has terminated
                    return Ok(());
                }
                if results.1.timed_out() {
                    break;
                }
            }

            // Since the waitid call on the main thread is using WNOWAIT, the
            // child process won't be cleaned up (until after this thread
            // exits and the main thread calls wait) and thus its PID won't be
            // reused by another, unrelated process.
            unsafe {
                let ret = libc::kill(pid as i32, libc::SIGTERM);
                if ret == -1 {
                    Err(io::Error::last_os_error())?
                }
            }

            Ok(())
        })
    };

    unsafe {
        // Block until the child process terminates, but leave it in a waitable
        // state still
        let ret = libc::waitid(
            libc::P_PID,
            pid,
            std::ptr::null_mut(),
            libc::WEXITED | libc::WNOWAIT,
        );
        if ret == -1 {
            Err(io::Error::last_os_error())?
        }
    }
    {
        let mut stop = stop_mutex.lock().unwrap();
        *stop = true;
    }
    // Tell the timeout thread to stop, wake it, and wait for it to exit
    condvar.notify_one();
    thread_handle.join().unwrap()?;

    // Clean up zombie and get exit status (this won't block, because the child
    // process has terminated and is still waitable)
    child.wait()
}

fn run_afl<I, S>(args: I, cmd: &str, timeout: Option<u64>)
where
    I: IntoIterator<Item = S>,
    S: AsRef<OsStr>,
{
    let cmd_path = common::afl_dir().join("bin").join(cmd);
    let mut cmd = Command::new(cmd_path);
    cmd.args(args);
    let status = run_timeout_terminate(cmd, timeout).unwrap();
    process::exit(status.code().unwrap_or(1));
}

fn run_cargo<I, S>(subcommand: &str, args: I)
where
    I: IntoIterator<Item = S>,
    S: AsRef<OsStr>,
{
    let cargo_path = env::var("CARGO").expect("Could not determine `cargo` path");

    // add some flags to sanitizers to make them work with Rust code
    let asan_options = env::var("ASAN_OPTIONS").unwrap_or_default();
    let asan_options = format!(
        "detect_odr_violation=0:abort_on_error=1:symbolize=0:{}",
        asan_options
    );

    let tsan_options = env::var("TSAN_OPTIONS").unwrap_or_default();
    let tsan_options = format!("report_signal_unsafe=0:{}", tsan_options);

    let version_meta = rustc_version::version_meta().unwrap();
    let passes = if version_meta.semver.minor >= 57
        && version_meta.llvm_version.map_or(true, |v| v.major >= 13)
    {
        // New LLVM pass manager is enabled when Rust 1.57+ and LLVM 13+
        // https://github.com/rust-lang/rust/pull/88243
        "sancov-module"
    } else {
        "sancov"
    };

    let mut rustflags = format!(
        "--cfg fuzzing \
         -C debug-assertions \
         -C overflow_checks \
         -C passes={} \
         -C llvm-args=-sanitizer-coverage-level=3 \
         -C llvm-args=-sanitizer-coverage-trace-pc-guard \
         -C llvm-args=-sanitizer-coverage-prune-blocks=0 \
         -C opt-level=3 \
         -C target-cpu=native \
         -C debuginfo=0 \
         -l afl-llvm-rt \
         -L {} ",
        passes,
        common::afl_llvm_rt_dir().display()
    );

    // RUSTFLAGS are not used by rustdoc, instead RUSTDOCFLAGS are used. Since
    // doctests will try to link against afl-llvm-rt, set up RUSTDOCFLAGS to
    // have doctests built the same as other code to avoid issues with doctests.
    let mut rustdocflags = format!(
        "--cfg fuzzing \
         -C debug-assertions \
         -C overflow_checks \
         -C passes={} \
         -C llvm-args=-sanitizer-coverage-level=3 \
         -C llvm-args=-sanitizer-coverage-trace-pc-guard \
         -C llvm-args=-sanitizer-coverage-prune-blocks=0 \
         -C opt-level=3 \
         -C target-cpu=native \
         -C debuginfo=0 \
         -L {} ",
        passes,
        common::afl_llvm_rt_dir().display()
    );

    if cfg!(target_os = "linux") {
        // work around https://github.com/rust-fuzz/afl.rs/issues/141 /
        // https://github.com/rust-lang/rust/issues/53945, can be removed once
        // those are fixed.
        rustflags.push_str("-Clink-arg=-fuse-ld=gold ");
        rustdocflags.push_str("-Clink-arg=-fuse-ld=gold ");
    }

    // add user provided flags
    rustflags.push_str(&env::var("RUSTFLAGS").unwrap_or_default());
    rustdocflags.push_str(&env::var("RUSTDOCFLAGS").unwrap_or_default());

    let status = Command::new(cargo_path)
        .arg(subcommand)
        .args(args)
        .env("RUSTFLAGS", &rustflags)
        .env("RUSTDOCFLAGS", &rustdocflags)
        .env("ASAN_OPTIONS", asan_options)
        .env("TSAN_OPTIONS", tsan_options)
        .status()
        .unwrap();
    process::exit(status.code().unwrap_or(1));
}
<commit_msg>Force 1 codegen unit<commit_after>use clap::{crate_version, value_t};

use std::env;
use std::ffi::OsStr;
use std::io;
use std::process::{self, Command, ExitStatus};
use std::sync::{Arc, Condvar, Mutex};
use std::thread;
use std::time::{Duration, Instant};

#[path = "../common.rs"]
mod common;

fn main() {
    if !common::archive_file_path().exists() {
        let version = common::afl_rustc_version();
        eprintln!(
            "AFL LLVM runtime is not built with Rust {}, run `cargo \
             install --force afl` to build it.",
            version
        );
        process::exit(1);
    }

    let app_matches = clap_app().get_matches();
    // This unwrap is okay because we set SubcommandRequiredElseHelp at the top level, and afl is
    // the only subcommand
    let afl_matches = app_matches.subcommand_matches("afl").unwrap();

    match afl_matches.subcommand() {
        ("analyze", Some(sub_matches)) => {
            let args = sub_matches
                .values_of_os("afl-analyze args")
                .unwrap_or_default();
            run_afl(args, "afl-analyze", None);
        }
        ("cmin", Some(sub_matches)) => {
            let args = sub_matches
                .values_of_os("afl-cmin args")
                .unwrap_or_default();
            run_afl(args, "afl-cmin", None);
        }
        ("fuzz", Some(sub_matches)) => {
            let args = sub_matches
                .values_of_os("afl-fuzz args")
                .unwrap_or_default();
            let timeout = sub_matches
                .value_of("max_total_time")
                .map(|_| value_t!(sub_matches, "max_total_time", u64).unwrap_or_else(|e| e.exit()));
            run_afl(args, "afl-fuzz", timeout);
        }
        ("gotcpu", Some(sub_matches)) => {
            let args = sub_matches
                .values_of_os("afl-gotcpu args")
                .unwrap_or_default();
            run_afl(args, "afl-gotcpu", None);
        }
        ("plot", Some(sub_matches)) => {
            let args = sub_matches
                .values_of_os("afl-plot args")
                .unwrap_or_default();
            run_afl(args, "afl-plot", None);
        }
        ("showmap", Some(sub_matches)) => {
            let args = sub_matches
                .values_of_os("afl-showmap args")
                .unwrap_or_default();
            run_afl(args, "afl-showmap", None);
        }
        ("tmin", Some(sub_matches)) => {
            let args = sub_matches
                .values_of_os("afl-tmin args")
                .unwrap_or_default();
            run_afl(args, "afl-tmin", None);
        }
        ("whatsup", Some(sub_matches)) => {
            let args = sub_matches
                .values_of_os("afl-whatsup args")
                .unwrap_or_default();
            run_afl(args, "afl-whatsup", None);
        }
        (subcommand, Some(sub_matches)) => {
            let args = sub_matches.values_of_os("").unwrap_or_default();
            run_cargo(subcommand, args);
        }
        // unreachable due to SubcommandRequiredElseHelp on "afl" subcommand
        (_, None) => unreachable!(),
    }
}

fn clap_app() -> clap::App<'static, 'static> {
    use clap::{
        App,
        AppSettings::{
            AllowExternalSubcommands, AllowLeadingHyphen, DisableHelpFlags, DisableHelpSubcommand,
            DisableVersion, SubcommandRequiredElseHelp,
        },
        Arg, SubCommand,
    };

    App::new("cargo afl")
        .bin_name("cargo")
        .setting(SubcommandRequiredElseHelp)
        .subcommand(
            SubCommand::with_name("afl")
                .version(crate_version!())
                .setting(SubcommandRequiredElseHelp)
                .setting(AllowExternalSubcommands)
                .usage("cargo afl [SUBCOMMAND or Cargo SUBCOMMAND]")
                .after_help(
                    "In addition to the subcommands above, Cargo subcommands are also \
                 supported (see `cargo help` for a list of all Cargo subcommands).",
                )
                .subcommand(
                    SubCommand::with_name("analyze")
                        .about("Invoke afl-analyze")
                        .setting(AllowLeadingHyphen)
                        .setting(DisableHelpSubcommand)
                        .setting(DisableHelpFlags)
                        .setting(DisableVersion)
                        .arg(Arg::with_name("afl-analyze args").multiple(true)),
                )
                .subcommand(
                    SubCommand::with_name("cmin")
                        .about("Invoke afl-cmin")
                        .setting(AllowLeadingHyphen)
                        .setting(DisableHelpSubcommand)
                        .setting(DisableHelpFlags)
                        .setting(DisableVersion)
                        .arg(Arg::with_name("afl-cmin args").multiple(true)),
                )
                .subcommand(
                    SubCommand::with_name("fuzz")
                        .about("Invoke afl-fuzz")
                        .setting(AllowLeadingHyphen)
                        .setting(DisableHelpSubcommand)
                        .setting(DisableHelpFlags)
                        .setting(DisableVersion)
                        .arg(
                            Arg::with_name("max_total_time")
                                .long("max_total_time")
                                .takes_value(true)
                                .help("Maximum amount of time to run the fuzzer"),
                        )
                        .arg(Arg::with_name("afl-fuzz args").multiple(true)),
                )
                .subcommand(
                    SubCommand::with_name("gotcpu")
                        .about("Invoke afl-gotcpu")
                        .setting(AllowLeadingHyphen)
                        .setting(DisableHelpSubcommand)
                        .setting(DisableHelpFlags)
                        .setting(DisableVersion)
                        .arg(Arg::with_name("afl-gotcpu args").multiple(true)),
                )
                .subcommand(
                    SubCommand::with_name("plot")
                        .about("Invoke afl-plot")
                        .setting(AllowLeadingHyphen)
                        .setting(DisableHelpSubcommand)
                        .setting(DisableHelpFlags)
                        .setting(DisableVersion)
                        .arg(Arg::with_name("afl-plot args").multiple(true)),
                )
                .subcommand(
                    SubCommand::with_name("showmap")
                        .about("Invoke afl-showmap")
                        .setting(AllowLeadingHyphen)
                        .setting(DisableHelpSubcommand)
                        .setting(DisableHelpFlags)
                        .setting(DisableVersion)
                        .arg(Arg::with_name("afl-showmap args").multiple(true)),
                )
                .subcommand(
                    SubCommand::with_name("tmin")
                        .about("Invoke afl-tmin")
                        .setting(AllowLeadingHyphen)
                        .setting(DisableHelpSubcommand)
                        .setting(DisableHelpFlags)
                        .setting(DisableVersion)
                        .arg(Arg::with_name("afl-tmin args").multiple(true)),
                )
                .subcommand(
                    SubCommand::with_name("whatsup")
                        .about("Invoke afl-whatsup")
                        .setting(AllowLeadingHyphen)
                        .setting(DisableHelpSubcommand)
                        .setting(DisableHelpFlags)
                        .setting(DisableVersion)
                        .arg(Arg::with_name("afl-whatsup args").multiple(true)),
                ),
        )
}

fn run_timeout_terminate(mut cmd: Command, timeout: Option<u64>) -> Result<ExitStatus, io::Error> {
    let timeout = match timeout {
        Some(timeout) => Duration::from_secs(timeout),
        None => return cmd.status(),
    };
    let start_time = Instant::now();

    let mut child = cmd.spawn()?;
    let pid = child.id();

    let pair = Arc::new((Mutex::new(false), Condvar::new()));
    let (stop_mutex, condvar) = &*pair;
    let thread_handle = {
        let pair = pair.clone();
        thread::spawn(move || -> Result<(), io::Error> {
            // This thread will wait until the child process has exited, or the
            // timeout has elapsed, whichever comes first. If the timeout
            // elapses, and the process is still running, it will send SIGTERM
            // to the child process.

            let (stop_mutex, condvar) = &*pair;
            let mut stop = stop_mutex.lock().unwrap();
            loop {
                let elapsed = Instant::now() - start_time;
                if elapsed >= timeout {
                    break;
                }

                let dur = timeout - elapsed;
                let results = condvar.wait_timeout(stop, dur).unwrap();
                stop = results.0;
                if *stop {
                    // Blocking waitid call on the main thread has returned,
                    // thus the child process has terminated
                    return Ok(());
                }
                if results.1.timed_out() {
                    break;
                }
            }

            // Since the waitid call on the main thread is using WNOWAIT, the
            // child process won't be cleaned up (until after this thread
            // exits and the main thread calls wait) and thus its PID won't be
            // reused by another, unrelated process.
            unsafe {
                let ret = libc::kill(pid as i32, libc::SIGTERM);
                if ret == -1 {
                    Err(io::Error::last_os_error())?
                }
            }

            Ok(())
        })
    };

    unsafe {
        // Block until the child process terminates, but leave it in a waitable
        // state still
        let ret = libc::waitid(
            libc::P_PID,
            pid,
            std::ptr::null_mut(),
            libc::WEXITED | libc::WNOWAIT,
        );
        if ret == -1 {
            Err(io::Error::last_os_error())?
        }
    }
    {
        let mut stop = stop_mutex.lock().unwrap();
        *stop = true;
    }
    // Tell the timeout thread to stop, wake it, and wait for it to exit
    condvar.notify_one();
    thread_handle.join().unwrap()?;

    // Clean up zombie and get exit status (this won't block, because the child
    // process has terminated and is still waitable)
    child.wait()
}

fn run_afl<I, S>(args: I, cmd: &str, timeout: Option<u64>)
where
    I: IntoIterator<Item = S>,
    S: AsRef<OsStr>,
{
    let cmd_path = common::afl_dir().join("bin").join(cmd);
    let mut cmd = Command::new(cmd_path);
    cmd.args(args);
    let status = run_timeout_terminate(cmd, timeout).unwrap();
    process::exit(status.code().unwrap_or(1));
}

fn run_cargo<I, S>(subcommand: &str, args: I)
where
    I: IntoIterator<Item = S>,
    S: AsRef<OsStr>,
{
    let cargo_path = env::var("CARGO").expect("Could not determine `cargo` path");

    // add some flags to sanitizers to make them work with Rust code
    let asan_options = env::var("ASAN_OPTIONS").unwrap_or_default();
    let asan_options = format!(
        "detect_odr_violation=0:abort_on_error=1:symbolize=0:{}",
        asan_options
    );

    let tsan_options = env::var("TSAN_OPTIONS").unwrap_or_default();
    let tsan_options = format!("report_signal_unsafe=0:{}", tsan_options);

    let version_meta = rustc_version::version_meta().unwrap();
    let passes = if version_meta.semver.minor >= 57
        && version_meta.llvm_version.map_or(true, |v| v.major >= 13)
    {
        // New LLVM pass manager is enabled when Rust 1.57+ and LLVM 13+
        // https://github.com/rust-lang/rust/pull/88243
        "sancov-module"
    } else {
        "sancov"
    };

    // `-C codegen-units=1` is needed to work around link errors
    // https://github.com/rust-fuzz/afl.rs/pull/193#issuecomment-933550430
    let mut rustflags = format!(
        "--cfg fuzzing \
         -C debug-assertions \
         -C overflow_checks \
         -C passes={} \
         -C codegen-units=1 \
         -C llvm-args=-sanitizer-coverage-level=3 \
         -C llvm-args=-sanitizer-coverage-trace-pc-guard \
         -C llvm-args=-sanitizer-coverage-prune-blocks=0 \
         -C opt-level=3 \
         -C target-cpu=native \
         -C debuginfo=0 \
         -l afl-llvm-rt \
         -L {} ",
        passes,
        common::afl_llvm_rt_dir().display()
    );

    // RUSTFLAGS are not used by rustdoc, instead RUSTDOCFLAGS are used. Since
    // doctests will try to link against afl-llvm-rt, set up RUSTDOCFLAGS to
    // have doctests built the same as other code to avoid issues with doctests.
    let mut rustdocflags = format!(
        "--cfg fuzzing \
         -C debug-assertions \
         -C overflow_checks \
         -C passes={} \
         -C codegen-units=1 \
         -C llvm-args=-sanitizer-coverage-level=3 \
         -C llvm-args=-sanitizer-coverage-trace-pc-guard \
         -C llvm-args=-sanitizer-coverage-prune-blocks=0 \
         -C opt-level=3 \
         -C target-cpu=native \
         -C debuginfo=0 \
         -L {} ",
        passes,
        common::afl_llvm_rt_dir().display()
    );

    if cfg!(target_os = "linux") {
        // work around https://github.com/rust-fuzz/afl.rs/issues/141 /
        // https://github.com/rust-lang/rust/issues/53945, can be removed once
        // those are fixed.
        rustflags.push_str("-Clink-arg=-fuse-ld=gold ");
        rustdocflags.push_str("-Clink-arg=-fuse-ld=gold ");
    }

    // add user provided flags
    rustflags.push_str(&env::var("RUSTFLAGS").unwrap_or_default());
    rustdocflags.push_str(&env::var("RUSTDOCFLAGS").unwrap_or_default());

    let status = Command::new(cargo_path)
        .arg(subcommand)
        .args(args)
        .env("RUSTFLAGS", &rustflags)
        .env("RUSTDOCFLAGS", &rustdocflags)
        .env("ASAN_OPTIONS", asan_options)
        .env("TSAN_OPTIONS", tsan_options)
        .status()
        .unwrap();
    process::exit(status.code().unwrap_or(1));
}
<|endoftext|>


<commit_before>use snafu::{ResultExt, Snafu};
use structopt::StructOpt;

use mimir::adapters::secondary::elasticsearch;
use mimir::domain::ports::secondary::remote::Remote;
use mimirsbrunn::settings::poi2mimir as settings;

#[derive(Debug, Snafu)]
pub enum Error {
    #[snafu(display("Settings (Configuration or CLI) Error: {}", source))]
    Settings { source: settings::Error },

    #[snafu(display("Elasticsearch Connection Pool {}", source))]
    ElasticsearchConnection {
        source: mimir::domain::ports::secondary::remote::Error,
    },

    #[snafu(display("Configuration Error {}", source))]
    Configuration { source: common::config::Error },

    #[snafu(display("Execution Error {}", source))]
    Execution { source: Box<dyn std::error::Error> },
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    let opts = settings::Opts::from_args();

    let settings = settings::Settings::new(&opts).context(Settings)?;

    match opts.cmd {
        settings::Command::Run => mimirsbrunn::utils::launch::wrapped_launch_async(
            &settings.logging.path.clone(),
            move || run(opts, settings),
        )
        .await
        .context(Execution),
        settings::Command::Config => {
            println!("{}", serde_json::to_string_pretty(&settings).unwrap());
            Ok(())
        }
    }
}

async fn run(
    opts: settings::Opts,
    settings: settings::Settings,
) -> Result<(), Box<dyn std::error::Error>> {
    let client = elasticsearch::remote::connection_pool_url(&settings.elasticsearch.url)
        .conn(settings.elasticsearch.clone())
        .await
        .context(ElasticsearchConnection)?;

    mimirsbrunn::pois::index_pois(opts.input, &client, settings.container).await?;

    Ok(())
}
<commit_msg>Add test for poi2mimir<commit_after>use snafu::{ResultExt, Snafu};
use structopt::StructOpt;

use mimir::adapters::secondary::elasticsearch;
use mimir::domain::ports::secondary::remote::Remote;
use mimirsbrunn::settings::poi2mimir as settings;

#[derive(Debug, Snafu)]
pub enum Error {
    #[snafu(display("Settings (Configuration or CLI) Error: {}", source))]
    Settings { source: settings::Error },

    #[snafu(display("Elasticsearch Connection Pool {}", source))]
    ElasticsearchConnection {
        source: mimir::domain::ports::secondary::remote::Error,
    },

    #[snafu(display("Configuration Error {}", source))]
    Configuration { source: common::config::Error },

    #[snafu(display("Execution Error {}", source))]
    Execution { source: Box<dyn std::error::Error> },
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    let opts = settings::Opts::from_args();

    let settings = settings::Settings::new(&opts).context(Settings)?;

    match opts.cmd {
        settings::Command::Run => mimirsbrunn::utils::launch::wrapped_launch_async(
            &settings.logging.path.clone(),
            move || run(opts, settings),
        )
        .await
        .context(Execution),
        settings::Command::Config => {
            println!("{}", serde_json::to_string_pretty(&settings).unwrap());
            Ok(())
        }
    }
}

async fn run(
    opts: settings::Opts,
    settings: settings::Settings,
) -> Result<(), Box<dyn std::error::Error>> {
    let client = elasticsearch::remote::connection_pool_url(&settings.elasticsearch.url)
        .conn(settings.elasticsearch.clone())
        .await
        .context(ElasticsearchConnection)?;

    mimirsbrunn::pois::index_pois(opts.input, &client, settings.container).await?;

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use futures::TryStreamExt;
    use mimir::adapters::secondary::elasticsearch::{remote, ElasticsearchStorageConfig};
    use mimir::domain::ports::primary::list_documents::ListDocuments;
    use mimir::utils::docker;
    use mimirsbrunn::settings::poi2mimir as settings;
    use places::poi::Poi;
    use serial_test::serial;

    #[tokio::test]
    #[serial]
    async fn should_correctly_index_poi_file() {
        docker::initialize()
            .await
            .expect("elasticsearch docker initialization");
        let opts = settings::Opts {
            config_dir: [env!("CARGO_MANIFEST_DIR"), "config"].iter().collect(),
            run_mode: Some("testing".to_string()),
            settings: vec![],
            input: [
                env!("CARGO_MANIFEST_DIR"),
                "tests",
                "fixtures",
                "poi",
                "keolis.poi",
            ]
            .iter()
            .collect(),
            cmd: settings::Command::Run,
        };

        let settings = settings::Settings::new(&opts).unwrap();
        let _res = mimirsbrunn::utils::launch::launch_async(move || run(opts, settings)).await;

        // Now we query the index we just created. Since it's a small cosmogony file with few entries,
        // we'll just list all the documents in the index, and check them.
        let config = ElasticsearchStorageConfig::default_testing();

        let client = remote::connection_pool_url(&config.url)
            .conn(config)
            .await
            .expect("Elasticsearch Connection Established");

        let pois: Vec<Poi> = client
            .list_documents()
            .await
            .unwrap()
            .try_collect()
            .await
            .unwrap();

        assert_eq!(pois.len(), 35);

        // let addr1 = addresses
        //     .iter()
        //     .find(|&addr| addr.name == "10 Place de la Mairie")
        //     .unwrap();

        // assert_eq!(addr1.id, "addr:1.378886;43.668175:10");
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Crowbook is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

extern crate clap;

use helpers::*;

use crowbook::{Result, Book, BookOptions, InfoLevel};
use crowbook_intl_runtime::set_lang;
use clap::ArgMatches;
use std::process::exit;
use std::fs::File;
use std::io;
use std::env;

/// Render a book to specific format
fn render_format(book: &mut Book, matches: &ArgMatches, format: &str) -> ! {
    let mut key = String::from("output.");
    key.push_str(format);
    let mut stdout = false;

    if let Some(file) = matches.value_of("output") {
        if file == "-" {
            stdout = true;
        } else {
            book.options.set(&key, file).unwrap();
        }
    }

    let res = book.options.get_path(&key);

    let result = match (res, stdout) {
        (Err(_), _) |
        (_, true)
        => {
            book.render_format_to(format, &mut io::stdout())
        }
        (Ok(file), false) => {
            book.render_format_to_file(format, file)
        }
    };

    match result {
        Err(err) => print_error(&format!("{}", err)),
        Ok(_) => {
            exit(0);
        }
    }
}

pub fn try_main() -> Result<()> {
    let lang = get_lang()
        .or_else(|| {
            match env::var("LANG") {
                Ok(val) => {
                    Some(val)
                },
                Err(_) => None,
            }
        });
    if let Some(val) = lang {
        if val.starts_with("fr") {
            set_lang("fr");
        } else {
            set_lang("en");
        }
    }

    let (matches, help, version) = create_matches();

    if matches.is_present("list-options") {
        println!("{}", BookOptions::description(false));
        exit(0);
    }

    if matches.is_present("list-options-md") {
        println!("{}", BookOptions::description(true));
        exit(0);
    }

    if matches.is_present("print-template") {
        let template = matches.value_of("print-template").unwrap();
        let mut book = Book::new();
        set_book_options(&mut book, &matches);
        let result = book.get_template(template.as_ref());
        match result {
            Ok(s) => {
                println!("{}", s);
                exit(0);
            }
            Err(_) => print_error(&lformat!("{} is not a valid template name.", template)),
        }
    }

    if matches.is_present("help") {
        println!("{}", help);
        exit(0);
    }

    if matches.is_present("version") {
        println!("{}", version);
        exit(0);
    }

    if matches.is_present("create") {
        create_book(&matches);
    }

    if !matches.is_present("BOOK") {
        print_error(&lformat!("You must pass the file of a book configuration \
                               file.\n\n{}\n\nFor more information try --help.",
                              matches.usage()));
    }

    // ok to unwrap since clap checks it's there
    let s = matches.value_of("BOOK").unwrap();
    let verbosity = if matches.is_present("debug") {
        InfoLevel::Debug
    } else if matches.is_present("verbose") {
        InfoLevel::Warning
    } else if matches.is_present("quiet") {
        InfoLevel::Quiet
    } else {
        InfoLevel::Info
    };

    let mut book = Book::new();
    book.set_verbosity(verbosity)
        .set_options(&get_book_options(&matches));

    if matches.is_present("single") {
        if s != "-" {
            book.load_markdown_file(s)?;
        } else {
            book.read_markdown_config(io::stdin())?;
        }
    } else {
        if s != "-" {
            book.load_file(s)?;
        } else {
            book.read_config(io::stdin())?;
        }
    }

    set_book_options(&mut book, &matches);
    if let Some(format) = matches.value_of("to") {
        render_format(&mut book, &matches, format);
    } else {
        book.render_all();
    }

    Ok(())
}

pub fn real_main() {
    match try_main() {
        Err(err) => print_error(&format!("{}", err)),
        Ok(_) => (),
    }
}
<commit_msg>Remove unnecessary import<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Crowbook is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

extern crate clap;

use helpers::*;

use crowbook::{Result, Book, BookOptions, InfoLevel};
use crowbook_intl_runtime::set_lang;
use clap::ArgMatches;
use std::process::exit;
use std::io;
use std::env;

/// Render a book to specific format
fn render_format(book: &mut Book, matches: &ArgMatches, format: &str) -> ! {
    let mut key = String::from("output.");
    key.push_str(format);
    let mut stdout = false;

    if let Some(file) = matches.value_of("output") {
        if file == "-" {
            stdout = true;
        } else {
            book.options.set(&key, file).unwrap();
        }
    }

    let res = book.options.get_path(&key);

    let result = match (res, stdout) {
        (Err(_), _) |
        (_, true)
        => {
            book.render_format_to(format, &mut io::stdout())
        }
        (Ok(file), false) => {
            book.render_format_to_file(format, file)
        }
    };

    match result {
        Err(err) => print_error(&format!("{}", err)),
        Ok(_) => {
            exit(0);
        }
    }
}

pub fn try_main() -> Result<()> {
    let lang = get_lang()
        .or_else(|| {
            match env::var("LANG") {
                Ok(val) => {
                    Some(val)
                },
                Err(_) => None,
            }
        });
    if let Some(val) = lang {
        if val.starts_with("fr") {
            set_lang("fr");
        } else {
            set_lang("en");
        }
    }

    let (matches, help, version) = create_matches();

    if matches.is_present("list-options") {
        println!("{}", BookOptions::description(false));
        exit(0);
    }

    if matches.is_present("list-options-md") {
        println!("{}", BookOptions::description(true));
        exit(0);
    }

    if matches.is_present("print-template") {
        let template = matches.value_of("print-template").unwrap();
        let mut book = Book::new();
        set_book_options(&mut book, &matches);
        let result = book.get_template(template.as_ref());
        match result {
            Ok(s) => {
                println!("{}", s);
                exit(0);
            }
            Err(_) => print_error(&lformat!("{} is not a valid template name.", template)),
        }
    }

    if matches.is_present("help") {
        println!("{}", help);
        exit(0);
    }

    if matches.is_present("version") {
        println!("{}", version);
        exit(0);
    }

    if matches.is_present("create") {
        create_book(&matches);
    }

    if !matches.is_present("BOOK") {
        print_error(&lformat!("You must pass the file of a book configuration \
                               file.\n\n{}\n\nFor more information try --help.",
                              matches.usage()));
    }

    // ok to unwrap since clap checks it's there
    let s = matches.value_of("BOOK").unwrap();
    let verbosity = if matches.is_present("debug") {
        InfoLevel::Debug
    } else if matches.is_present("verbose") {
        InfoLevel::Warning
    } else if matches.is_present("quiet") {
        InfoLevel::Quiet
    } else {
        InfoLevel::Info
    };

    let mut book = Book::new();
    book.set_verbosity(verbosity)
        .set_options(&get_book_options(&matches));

    if matches.is_present("single") {
        if s != "-" {
            book.load_markdown_file(s)?;
        } else {
            book.read_markdown_config(io::stdin())?;
        }
    } else {
        if s != "-" {
            book.load_file(s)?;
        } else {
            book.read_config(io::stdin())?;
        }
    }

    set_book_options(&mut book, &matches);
    if let Some(format) = matches.value_of("to") {
        render_format(&mut book, &matches, format);
    } else {
        book.render_all();
    }

    Ok(())
}

pub fn real_main() {
    match try_main() {
        Err(err) => print_error(&format!("{}", err)),
        Ok(_) => (),
    }
}
<|endoftext|>


<commit_before>use std;

use cgmath::Point2;
use gfx;
use specs;
use specs::prelude::{Read, ReadStorage, WriteStorage};

use crate::character::{character_stats::CharacterStats, controls::CharacterInputState};
use crate::critter::{CharacterSprite, CritterData};
use crate::data;
use crate::game::constants::{AMMO_POSITIONS, ASPECT_RATIO, CHARACTER_SHEET_TOTAL_WIDTH, RUN_SPRITE_OFFSET, SPRITE_OFFSET, VIEW_DISTANCE};
use crate::gfx_app::{ColorFormat, DepthFormat};
use crate::gfx_app::mouse_controls::MouseInputState;
use crate::graphics::{camera::CameraInputState, dimensions::{Dimensions, get_projection, get_view_matrix}, get_orientation_from_center, orientation::{Orientation, Stance}, overlaps, texture::load_texture};
use crate::graphics::mesh::{RectangularTexturedMesh, Geometry};
use crate::graphics::texture::Texture;
use crate::shaders::{CharacterSheet, critter_pipeline, Position, Projection};
use crate::terrain_object::{terrain_objects::TerrainObjects, TerrainObjectDrawable, TerrainTexture};
use crate::zombie::{ZombieDrawable, zombies::Zombies};

pub mod controls;
mod character_stats;

const SHADER_VERT: &[u8] = include_bytes!("../shaders/character.v.glsl");
const SHADER_FRAG: &[u8] = include_bytes!("../shaders/character.f.glsl");

#[derive(Clone)]
pub struct CharacterDrawable {
  pub stats: CharacterStats,
  projection: Projection,
  pub position: Position,
  orientation: Orientation,
  pub stance: Stance,
  direction: Orientation,
}

impl CharacterDrawable {
  pub fn new() -> CharacterDrawable {
    let view = get_view_matrix(VIEW_DISTANCE);
    let projection = get_projection(view, ASPECT_RATIO);
    let stats = CharacterStats::new();
    CharacterDrawable {
      stats,
      projection,
      position: Position::origin(),
      orientation: Orientation::Right,
      stance: Stance::Walking,
      direction: Orientation::Right,
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &CharacterInputState, mouse_input: &MouseInputState,
                dimensions: &Dimensions, objs: &mut Vec<TerrainObjectDrawable>, zombies: &[ZombieDrawable]) {
    self.projection = *world_to_clip;

    fn zombie_not_dead(z: &ZombieDrawable) -> bool {
      z.stance != Stance::NormalDeath &&
        z.stance != Stance::CriticalDeath
    }

    for idx in 0..AMMO_POSITIONS.len() {
      self.ammo_pick_up(ci.movement, objs, idx);
    }

    if !cfg!(feature = "godmode") &&
      zombies.iter()
        .any(|z|
          zombie_not_dead(z) &&
            overlaps(ci.movement,
                     ci.movement - z.position,
                     15.0,
                     30.0)) {
      self.stance = Stance::NormalDeath;
      println!("Player died");
      std::process::exit(0);
    }

    if ci.is_shooting && mouse_input.left_click_point.is_some() && !ci.is_colliding {
      self.stance = Stance::Firing;
      self.orientation = get_orientation_from_center(mouse_input, dimensions);
    } else if ci.is_colliding {
      self.stance = Stance::Still;
    } else {
      self.stance = Stance::Walking;
      self.orientation = ci.orientation;
    }
  }

  fn ammo_pick_up(&mut self, movement: Position, objs: &mut Vec<TerrainObjectDrawable>, idx: usize) {
    if objs[idx].object_type == TerrainTexture::Ammo && overlaps(movement, movement - objs[idx].position, 20.0, 20.0) {
      self.stats.magazines = 2;
      objs.remove(idx);
    }
  }
}

impl Default for CharacterDrawable {
  fn default() -> Self {
    CharacterDrawable::new()
  }
}

impl specs::prelude::Component for CharacterDrawable {
  type Storage = specs::storage::VecStorage<CharacterDrawable>;
}

pub struct CharacterDrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, critter_pipeline::Data<R>>,
  data: Vec<CritterData>,
}

impl<R: gfx::Resources> CharacterDrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> CharacterDrawSystem<R>
    where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let charter_bytes = &include_bytes!("../../assets/character.png")[..];
    let char_texture = load_texture(factory, charter_bytes);

    let rect_mesh =
      RectangularTexturedMesh::new(factory, Texture::new(char_texture, None), Geometry::Rectangle, Point2::new(20.0, 28.0), None, None, None);

    let pso = factory.create_pipeline_simple(SHADER_VERT, SHADER_FRAG, critter_pipeline::new())
      .expect("Character shader loading error");

    let pipeline_data = critter_pipeline::Data {
      vbuf: rect_mesh.mesh.vertex_buffer,
      projection_cb: factory.create_constant_buffer(1),
      position_cb: factory.create_constant_buffer(1),
      character_sprite_cb: factory.create_constant_buffer(1),
      charactersheet: (rect_mesh.mesh.texture.raw, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let data = data::load_character();

    CharacterDrawSystem {
      bundle: gfx::Bundle::new(rect_mesh.mesh.slice, pso, pipeline_data),
      data,
    }
  }

  fn get_next_sprite(&self, character_idx: usize, character_fire_idx: usize, drawable: &mut CharacterDrawable) -> CharacterSheet {
    let sprite_idx =
      if drawable.orientation == Orientation::Normal && drawable.stance == Stance::Walking {
        (drawable.direction as usize * 28 + RUN_SPRITE_OFFSET)
      } else if drawable.stance == Stance::Walking {
        drawable.direction = drawable.orientation;
        (drawable.orientation as usize * 28 + character_idx + RUN_SPRITE_OFFSET)
      } else {
        (drawable.orientation as usize * 8 + character_fire_idx)
      } as usize;

    let elements_x = CHARACTER_SHEET_TOTAL_WIDTH / (self.data[sprite_idx].data[2] + SPRITE_OFFSET);
    CharacterSheet {
      x_div: elements_x,
      y_div: 0.0,
      row_idx: 0,
      index: sprite_idx as f32,
    }
  }

  pub fn draw<C>(&mut self,
                 mut drawable: &mut CharacterDrawable,
                 character: &CharacterSprite,
                 encoder: &mut gfx::Encoder<R, C>)
    where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    encoder.update_constant_buffer(&self.bundle.data.character_sprite_cb,
                                   &self.get_next_sprite(character.character_idx,
                                                         character.character_fire_idx,
                                                         &mut drawable));
    self.bundle.encode(encoder);
  }
}

pub struct PreDrawSystem;

impl<'a> specs::prelude::System<'a> for PreDrawSystem {
  type SystemData = (WriteStorage<'a, CharacterDrawable>,
                     ReadStorage<'a, CameraInputState>,
                     ReadStorage<'a, CharacterInputState>,
                     ReadStorage<'a, MouseInputState>,
                     WriteStorage<'a, TerrainObjects>,
                     ReadStorage<'a, Zombies>,
                     Read<'a, Dimensions>);

  fn run(&mut self, (mut character, camera_input, character_input, mouse_input, mut terrain_objects, zombies, dim): Self::SystemData) {
    use specs::join::Join;

    for (c, camera, ci, mi, to, zs) in (&mut character, &camera_input, &character_input, &mouse_input, &mut terrain_objects, &zombies).join() {
      let world_to_clip = dim.world_to_projection(camera);
      c.update(&world_to_clip, ci, mi, &dim, &mut to.objects, &zs.zombies);
    }
  }
}
<commit_msg>Add length (safety) check <commit_after>use std;

use cgmath::Point2;
use gfx;
use specs;
use specs::prelude::{Read, ReadStorage, WriteStorage};

use crate::character::{character_stats::CharacterStats, controls::CharacterInputState};
use crate::critter::{CharacterSprite, CritterData};
use crate::data;
use crate::game::constants::{AMMO_POSITIONS, ASPECT_RATIO, CHARACTER_SHEET_TOTAL_WIDTH, RUN_SPRITE_OFFSET, SPRITE_OFFSET, VIEW_DISTANCE};
use crate::gfx_app::{ColorFormat, DepthFormat};
use crate::gfx_app::mouse_controls::MouseInputState;
use crate::graphics::{camera::CameraInputState, dimensions::{Dimensions, get_projection, get_view_matrix}, get_orientation_from_center, orientation::{Orientation, Stance}, overlaps, texture::load_texture};
use crate::graphics::mesh::{RectangularTexturedMesh, Geometry};
use crate::graphics::texture::Texture;
use crate::shaders::{CharacterSheet, critter_pipeline, Position, Projection};
use crate::terrain_object::{terrain_objects::TerrainObjects, TerrainObjectDrawable, TerrainTexture};
use crate::zombie::{ZombieDrawable, zombies::Zombies};

pub mod controls;
mod character_stats;

const SHADER_VERT: &[u8] = include_bytes!("../shaders/character.v.glsl");
const SHADER_FRAG: &[u8] = include_bytes!("../shaders/character.f.glsl");

#[derive(Clone)]
pub struct CharacterDrawable {
  pub stats: CharacterStats,
  projection: Projection,
  pub position: Position,
  orientation: Orientation,
  pub stance: Stance,
  direction: Orientation,
}

impl CharacterDrawable {
  pub fn new() -> CharacterDrawable {
    let view = get_view_matrix(VIEW_DISTANCE);
    let projection = get_projection(view, ASPECT_RATIO);
    let stats = CharacterStats::new();
    CharacterDrawable {
      stats,
      projection,
      position: Position::origin(),
      orientation: Orientation::Right,
      stance: Stance::Walking,
      direction: Orientation::Right,
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &CharacterInputState, mouse_input: &MouseInputState,
                dimensions: &Dimensions, objs: &mut Vec<TerrainObjectDrawable>, zombies: &[ZombieDrawable]) {
    self.projection = *world_to_clip;

    fn zombie_not_dead(z: &ZombieDrawable) -> bool {
      z.stance != Stance::NormalDeath &&
        z.stance != Stance::CriticalDeath
    }

    for idx in 0..AMMO_POSITIONS.len() {
      self.ammo_pick_up(ci.movement, objs, idx);
    }

    if !cfg!(feature = "godmode") &&
      zombies.iter()
        .any(|z|
          zombie_not_dead(z) &&
            overlaps(ci.movement,
                     ci.movement - z.position,
                     15.0,
                     30.0)) {
      self.stance = Stance::NormalDeath;
      println!("Player died");
      std::process::exit(0);
    }

    if ci.is_shooting && mouse_input.left_click_point.is_some() && !ci.is_colliding {
      self.stance = Stance::Firing;
      self.orientation = get_orientation_from_center(mouse_input, dimensions);
    } else if ci.is_colliding {
      self.stance = Stance::Still;
    } else {
      self.stance = Stance::Walking;
      self.orientation = ci.orientation;
    }
  }

  fn ammo_pick_up(&mut self, movement: Position, objs: &mut Vec<TerrainObjectDrawable>, idx: usize) {
    if objs.len() > idx && objs[idx].object_type == TerrainTexture::Ammo && overlaps(movement, movement - objs[idx].position, 20.0, 20.0) {
      self.stats.magazines = 2;
      objs.remove(idx);
    }
  }
}

impl Default for CharacterDrawable {
  fn default() -> Self {
    CharacterDrawable::new()
  }
}

impl specs::prelude::Component for CharacterDrawable {
  type Storage = specs::storage::VecStorage<CharacterDrawable>;
}

pub struct CharacterDrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, critter_pipeline::Data<R>>,
  data: Vec<CritterData>,
}

impl<R: gfx::Resources> CharacterDrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> CharacterDrawSystem<R>
    where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let charter_bytes = &include_bytes!("../../assets/character.png")[..];
    let char_texture = load_texture(factory, charter_bytes);

    let rect_mesh =
      RectangularTexturedMesh::new(factory, Texture::new(char_texture, None), Geometry::Rectangle, Point2::new(20.0, 28.0), None, None, None);

    let pso = factory.create_pipeline_simple(SHADER_VERT, SHADER_FRAG, critter_pipeline::new())
      .expect("Character shader loading error");

    let pipeline_data = critter_pipeline::Data {
      vbuf: rect_mesh.mesh.vertex_buffer,
      projection_cb: factory.create_constant_buffer(1),
      position_cb: factory.create_constant_buffer(1),
      character_sprite_cb: factory.create_constant_buffer(1),
      charactersheet: (rect_mesh.mesh.texture.raw, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let data = data::load_character();

    CharacterDrawSystem {
      bundle: gfx::Bundle::new(rect_mesh.mesh.slice, pso, pipeline_data),
      data,
    }
  }

  fn get_next_sprite(&self, character_idx: usize, character_fire_idx: usize, drawable: &mut CharacterDrawable) -> CharacterSheet {
    let sprite_idx =
      if drawable.orientation == Orientation::Normal && drawable.stance == Stance::Walking {
        (drawable.direction as usize * 28 + RUN_SPRITE_OFFSET)
      } else if drawable.stance == Stance::Walking {
        drawable.direction = drawable.orientation;
        (drawable.orientation as usize * 28 + character_idx + RUN_SPRITE_OFFSET)
      } else {
        (drawable.orientation as usize * 8 + character_fire_idx)
      } as usize;

    let elements_x = CHARACTER_SHEET_TOTAL_WIDTH / (self.data[sprite_idx].data[2] + SPRITE_OFFSET);
    CharacterSheet {
      x_div: elements_x,
      y_div: 0.0,
      row_idx: 0,
      index: sprite_idx as f32,
    }
  }

  pub fn draw<C>(&mut self,
                 mut drawable: &mut CharacterDrawable,
                 character: &CharacterSprite,
                 encoder: &mut gfx::Encoder<R, C>)
    where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    encoder.update_constant_buffer(&self.bundle.data.character_sprite_cb,
                                   &self.get_next_sprite(character.character_idx,
                                                         character.character_fire_idx,
                                                         &mut drawable));
    self.bundle.encode(encoder);
  }
}

pub struct PreDrawSystem;

impl<'a> specs::prelude::System<'a> for PreDrawSystem {
  type SystemData = (WriteStorage<'a, CharacterDrawable>,
                     ReadStorage<'a, CameraInputState>,
                     ReadStorage<'a, CharacterInputState>,
                     ReadStorage<'a, MouseInputState>,
                     WriteStorage<'a, TerrainObjects>,
                     ReadStorage<'a, Zombies>,
                     Read<'a, Dimensions>);

  fn run(&mut self, (mut character, camera_input, character_input, mouse_input, mut terrain_objects, zombies, dim): Self::SystemData) {
    use specs::join::Join;

    for (c, camera, ci, mi, to, zs) in (&mut character, &camera_input, &character_input, &mouse_input, &mut terrain_objects, &zombies).join() {
      let world_to_clip = dim.world_to_projection(camera);
      c.update(&world_to_clip, ci, mi, &dim, &mut to.objects, &zs.zombies);
    }
  }
}
<|endoftext|>


<commit_before>use ir;
use std::io::prelude::*;
use std::io;
use itertools::Itertools;

pub fn gen_translation_unit<F: Write>(f: &mut F, tu: ir::TranslationUnit) -> io::Result<()> {
    writeln!(f, "#include <stdlib.h>")?;
    writeln!(f, "#include <stdio.h>\n")?;

    writeln!(f, "void print_int(int a) {{")?;
    writeln!(f, "\tprintf(\"%d\\n\", a);")?;
    writeln!(f, "}}")?;

    for declaration in tu.declarations {
        gen_declaration(f, declaration)?;
    }
    Ok(())
}

fn gen_declaration<F: Write>(f: &mut F, declaration: ir::Declaration) -> io::Result<()> {
    match declaration {
        ir::Declaration::ExternFunction { name, ty } => {
            writeln!(f,
                     "extern {} {}({});",
                     type_to_string(*ty.return_ty),
                     name,
                     ty.params_ty.into_iter().map(type_to_string).join(", "))?;
        }
        ir::Declaration::Function {
            name,
            ty,
            locals,
            bbs,
        } => {
            writeln!(f,
                     "{} {}({}) {{",
                     type_to_string(*ty.return_ty),
                     name,
                     ty.params_ty
                         .into_iter()
                         .map(type_to_string)
                         .enumerate()
                         .map(|(index, ty)| format!("{} arg{}", ty, index))
                         .join(", "))?;

            for local in locals {
                gen_local(f, local)?;
            }
            writeln!(f, "")?;
            for bb in bbs {
                gen_basic_block(f, bb)?;
            }

            writeln!(f, "}}")?;
        }
    }
    Ok(())
}

fn gen_local<F: Write>(f: &mut F, local: ir::LocalVar) -> io::Result<()> {
    writeln!(f,
             "\t{}{};",
             type_to_string_with_name(local.ty, format!("local_{}", local.id.0)),
             local
                 .param_index
                 .map(|index| format!(" = arg{}", index))
                 .unwrap_or(String::new()))
}

fn gen_basic_block<F: Write>(f: &mut F, bb: ir::BasicBlock) -> io::Result<()> {
    writeln!(f, "bb{}: {{", bb.id.0)?;
    for stmt in bb.stmts {
        gen_statement(f, stmt)?;
    }

    gen_terminator(f, bb.terminator)?;
    writeln!(f, "}}")?;
    Ok(())
}

fn gen_statement<F: Write>(f: &mut F, stmt: ir::Statement) -> io::Result<()> {
    match stmt {
        ir::Statement::LValueSet(dest, val) => {
            writeln!(f, "\t*temp_{} = temp_{};", dest.id, val.id)
        }
        ir::Statement::Assign(dest, expr) => {
            if dest.ty != ir::Type::Unit {
                write!(f,
                       "\t{} = ",
                       type_to_string_with_name(dest.ty, format!("temp_{}", dest.id)))?;
            }
            gen_expr(f, expr)?;
            writeln!(f, ";")
        }
    }
}

fn gen_expr<F: Write>(f: &mut F, expr: ir::Expression) -> io::Result<()> {
    match expr {
        ir::Expression::LocalVarLoad(id) => write!(f, "&local_{}", id.0),
        ir::Expression::GlobalLoad(name) => write!(f, "{}", name),
        ir::Expression::LValueLoad(val) => write!(f, "*temp_{}", val.id),
        ir::Expression::BinOp(op, lhs, rhs) => {
            use ir::BinOpCode::*;
            let op = match op {
                PtrAdd | IntAdd | DoubleAdd => "+",
                IntSub | DoubleSub => "-",
                IntTimes | DoubleTimes => "*",
                IntDivide | DoubleDivide => "/",
                IntMod => "%",
                IntLess | DoubleLess => "<",
                IntLessEqual | DoubleLessEqual => "<=",
                IntGreater | DoubleGreater => ">",
                IntGreaterEqual | DoubleGreaterEqual => ">=",
                IntEqual | DoubleEqual | BoolEqual => "==",
                IntNotEqual | DoubleNotEqual | BoolNotEqual => "!=",
                // BoolLogicalAnd => "&&",
                // BoolLogicalOr => "||",
            };

            write!(f, "temp_{} {} temp_{}", lhs.id, op, rhs.id)
        }
        ir::Expression::UnOp(op, sub) => {
            use ir::UnOpCode::*;
            let op = match op {
                IntMinus | DoubleMinus => "-",
                BoolLogicalNot => "!",
                AddressOf => "&",
                PtrDeref => "*",
            };

            write!(f, "{}temp_{}", op, sub.id)
        }
        ir::Expression::CastOp(op, expr) => {
            use ir::CastCode::*;
            let target_ty = match op {
                IntToDouble => "double",
                DoubleToInt => "int",
                IntToChar => "char",
                CharToInt => "int",
                IntToBool => "bool",
                BoolToInt => "int",
            };
            write!(f, "(({})temp_{})", target_ty, expr.id)
        }
        ir::Expression::ReadArray(array, index) => {
            write!(f, "temp_{}[temp_{}]", array.id, index.id)
        }
        ir::Expression::FuncCall(func, params) => {
            write!(f,
                   "temp_{}({})",
                   func.id,
                   params
                       .into_iter()
                       .map(|val| format!("temp_{}", val.id))
                       .join(", "))
        }
        ir::Expression::Literal(lit) => {
            match lit {
                ir::Literal::Int(val) => write!(f, "{}", val),
                ir::Literal::Double(val) => write!(f, "{}", val),
                ir::Literal::Bool(val) => write!(f, "{}", if val { 1 } else { 0 }),
                ir::Literal::Char(val) => write!(f, "{}", val),
                ir::Literal::Unit => Ok(()),
            }
        }
    }
}

fn gen_terminator<F: Write>(f: &mut F, term: ir::Terminator) -> io::Result<()> {
    match term {
        ir::Terminator::Br(id) => writeln!(f, "\tgoto bb{};", id.0),
        ir::Terminator::BrCond(value, id1, id2) => {
            writeln!(f,
                     "\tif (temp_{}) {{ goto bb{}; }} else {{ goto bb{}; }}",
                     value.id,
                     id1.0,
                     id2.0)
        }
        ir::Terminator::Ret(value) => {
            if value.ty != ir::Type::Unit {
                writeln!(f, "\treturn temp_{};", value.id)
            } else {
                writeln!(f, "\treturn;")
            }
        },
    }
}

fn type_to_string_with_name(ty: ir::Type, name: String) -> String {
    match ty {
        ir::Type::Unit => format!("void {}", name),
        ir::Type::Bool => format!("int {}", name), // cause c you know
        ir::Type::Int => format!("int {}", name),
        ir::Type::Double => format!("double {}", name),
        ir::Type::Char => format!("char {}", name),
        ir::Type::LValue(sub) => format!("{} *{}", type_to_string(*sub), name),
        ir::Type::Array(sub, size) => format!("{} {}[{}]", type_to_string(*sub), name, size),
        ir::Type::Ptr(sub) => format!("{} *{}", type_to_string(*sub), name),
        ir::Type::Function(func) => {
            format!("{}(*{})({})",
                    type_to_string(*func.return_ty),
                    name,
                    func.params_ty
                        .into_iter()
                        .map(type_to_string)
                        .join(", "))
        }
    }
}

fn type_to_string(ty: ir::Type) -> String {
    match ty {
        ir::Type::Unit => format!("void"),
        ir::Type::Bool => format!("int"), // cause c you know
        ir::Type::Int => format!("int"),
        ir::Type::Double => format!("double"),
        ir::Type::Char => format!("char"),
        ir::Type::LValue(sub) => format!("{}*", type_to_string(*sub)),
        ir::Type::Array(sub, size) => format!("{}[{}]", type_to_string(*sub), size),
        ir::Type::Ptr(sub) => format!("{}*", type_to_string(*sub)),
        ir::Type::Function(func) => {
            format!("{}(*)({})",
                    type_to_string(*func.return_ty),
                    func.params_ty
                        .into_iter()
                        .map(type_to_string)
                        .join(", "))
        }
    }
}
<commit_msg>Just nothing<commit_after>use ir;
use std::io::prelude::*;
use std::io;
use itertools::Itertools;

pub fn gen_translation_unit<F: Write>(f: &mut F, tu: ir::TranslationUnit) -> io::Result<()> {
    writeln!(f, "#include <stdlib.h>")?;
    writeln!(f, "#include <stdio.h>\n")?;

    writeln!(f, "void print_int(int a) {{")?;
    writeln!(f, "\tprintf(\"%d\\n\", a);")?;
    writeln!(f, "}}")?;

    for declaration in tu.declarations {
        gen_declaration(f, declaration)?;
    }
    Ok(())
}

fn gen_declaration<F: Write>(f: &mut F, declaration: ir::Declaration) -> io::Result<()> {
    match declaration {
        ir::Declaration::ExternFunction { name, ty } => {
            writeln!(f,
                     "extern {} {}({});",
                     type_to_string(*ty.return_ty),
                     name,
                     ty.params_ty.into_iter().map(type_to_string).join(", "))?;
        }
        ir::Declaration::Function {
            name,
            ty,
            locals,
            bbs,
        } => {
            writeln!(f,
                     "{} {}({}) {{",
                     type_to_string(*ty.return_ty),
                     name,
                     ty.params_ty
                         .into_iter()
                         .map(type_to_string)
                         .enumerate()
                         .map(|(index, ty)| format!("{} arg{}", ty, index))
                         .join(", "))?;

            for local in locals {
                gen_local(f, local)?;
            }
            writeln!(f, "")?;
            for bb in bbs {
                gen_basic_block(f, bb)?;
            }

            writeln!(f, "}}")?;
        }
    }
    Ok(())
}

fn gen_local<F: Write>(f: &mut F, local: ir::LocalVar) -> io::Result<()> {
    writeln!(f,
             "\t{}{};",
             type_to_string_with_name(local.ty, format!("local_{}", local.id.0)),
             local
                 .param_index
                 .map(|index| format!(" = arg{}", index))
                 .unwrap_or(String::new()))
}

fn gen_basic_block<F: Write>(f: &mut F, bb: ir::BasicBlock) -> io::Result<()> {
    writeln!(f, "bb{}: {{", bb.id.0)?;
    for stmt in bb.stmts {
        gen_statement(f, stmt)?;
    }

    gen_terminator(f, bb.terminator)?;
    writeln!(f, "}}")?;
    Ok(())
}

fn gen_statement<F: Write>(f: &mut F, stmt: ir::Statement) -> io::Result<()> {
    match stmt {
        ir::Statement::LValueSet(dest, val) => {
            writeln!(f, "\t*temp_{} = temp_{};", dest.id, val.id)
        }
        ir::Statement::Assign(dest, expr) => {
            if dest.ty != ir::Type::Unit {
                write!(f,
                       "\t{} = ",
                       type_to_string_with_name(dest.ty, format!("temp_{}", dest.id)))?;
            }
            gen_expr(f, expr)?;
            writeln!(f, ";")
        }
    }
}

fn gen_expr<F: Write>(f: &mut F, expr: ir::Expression) -> io::Result<()> {
    match expr {
        ir::Expression::LocalVarLoad(id) => write!(f, "&local_{}", id.0),
        ir::Expression::GlobalLoad(name) => write!(f, "{}", name),
        ir::Expression::LValueLoad(val) => write!(f, "*temp_{}", val.id),
        ir::Expression::BinOp(op, lhs, rhs) => {
            use ir::BinOpCode::*;
            let op = match op {
                PtrAdd | IntAdd | DoubleAdd => "+",
                IntSub | DoubleSub => "-",
                IntTimes | DoubleTimes => "*",
                IntDivide | DoubleDivide => "/",
                IntMod => "%",
                IntLess | DoubleLess => "<",
                IntLessEqual | DoubleLessEqual => "<=",
                IntGreater | DoubleGreater => ">",
                IntGreaterEqual | DoubleGreaterEqual => ">=",
                IntEqual | DoubleEqual | BoolEqual => "==",
                IntNotEqual | DoubleNotEqual | BoolNotEqual => "!=",
            };

            write!(f, "temp_{} {} temp_{}", lhs.id, op, rhs.id)
        }
        ir::Expression::UnOp(op, sub) => {
            use ir::UnOpCode::*;
            let op = match op {
                IntMinus | DoubleMinus => "-",
                BoolLogicalNot => "!",
                AddressOf => "&",
                PtrDeref => "*",
            };

            write!(f, "{}temp_{}", op, sub.id)
        }
        ir::Expression::CastOp(op, expr) => {
            use ir::CastCode::*;
            let target_ty = match op {
                IntToDouble => "double",
                DoubleToInt => "int",
                IntToChar => "char",
                CharToInt => "int",
                IntToBool => "bool",
                BoolToInt => "int",
            };
            write!(f, "(({})temp_{})", target_ty, expr.id)
        }
        ir::Expression::ReadArray(array, index) => {
            write!(f, "temp_{}[temp_{}]", array.id, index.id)
        }
        ir::Expression::FuncCall(func, params) => {
            write!(f,
                   "temp_{}({})",
                   func.id,
                   params
                       .into_iter()
                       .map(|val| format!("temp_{}", val.id))
                       .join(", "))
        }
        ir::Expression::Literal(lit) => {
            match lit {
                ir::Literal::Int(val) => write!(f, "{}", val),
                ir::Literal::Double(val) => write!(f, "{}", val),
                ir::Literal::Bool(val) => write!(f, "{}", if val { 1 } else { 0 }),
                ir::Literal::Char(val) => write!(f, "{}", val),
                ir::Literal::Unit => Ok(()),
            }
        }
    }
}

fn gen_terminator<F: Write>(f: &mut F, term: ir::Terminator) -> io::Result<()> {
    match term {
        ir::Terminator::Br(id) => writeln!(f, "\tgoto bb{};", id.0),
        ir::Terminator::BrCond(value, id1, id2) => {
            writeln!(f,
                     "\tif (temp_{}) {{ goto bb{}; }} else {{ goto bb{}; }}",
                     value.id,
                     id1.0,
                     id2.0)
        }
        ir::Terminator::Ret(value) => {
            if value.ty != ir::Type::Unit {
                writeln!(f, "\treturn temp_{};", value.id)
            } else {
                writeln!(f, "\treturn;")
            }
        },
    }
}

fn type_to_string_with_name(ty: ir::Type, name: String) -> String {
    match ty {
        ir::Type::Unit => format!("void {}", name),
        ir::Type::Bool => format!("int {}", name), // cause c you know
        ir::Type::Int => format!("int {}", name),
        ir::Type::Double => format!("double {}", name),
        ir::Type::Char => format!("char {}", name),
        ir::Type::LValue(sub) => format!("{} *{}", type_to_string(*sub), name),
        ir::Type::Array(sub, size) => format!("{} {}[{}]", type_to_string(*sub), name, size),
        ir::Type::Ptr(sub) => format!("{} *{}", type_to_string(*sub), name),
        ir::Type::Function(func) => {
            format!("{}(*{})({})",
                    type_to_string(*func.return_ty),
                    name,
                    func.params_ty
                        .into_iter()
                        .map(type_to_string)
                        .join(", "))
        }
    }
}

fn type_to_string(ty: ir::Type) -> String {
    match ty {
        ir::Type::Unit => format!("void"),
        ir::Type::Bool => format!("int"), // cause c you know
        ir::Type::Int => format!("int"),
        ir::Type::Double => format!("double"),
        ir::Type::Char => format!("char"),
        ir::Type::LValue(sub) => format!("{}*", type_to_string(*sub)),
        ir::Type::Array(sub, size) => format!("{}[{}]", type_to_string(*sub), size),
        ir::Type::Ptr(sub) => format!("{}*", type_to_string(*sub)),
        ir::Type::Function(func) => {
            format!("{}(*)({})",
                    type_to_string(*func.return_ty),
                    func.params_ty
                        .into_iter()
                        .map(type_to_string)
                        .join(", "))
        }
    }
}
<|endoftext|>


<commit_before>//! Encoding and decoding of the (16, 8, 5) shortened cyclic code described by P25.
//!
//! The parity-check matrix construction was sourced from \[1] and the decoding algorithm
//! was derived from \[2]. The key information that this code is shortened from a (17, 8,
//! 5) code came from \[3].
//!
//! \[1]: "Coding Theory and Cryptography: The Essentials", 2nd ed, Hankerson, Hoffman, et
//! al, 2000
//! \[2]: "Error Control Coding", Lin and Costello, 1983
//! \[3]: "Standard APCO25 Physical Layer of the Radio Transmission Chain", Simon, 2014

/// Encode the 8 data bits into a 16-bit codeword.
pub fn encode(data: u8) -> u16 {
    matrix_mul_systematic!(data, GEN, u16)
}

/// Try to decode the 16-bit word to the nearest codeword, correcting up to 2 errors.
/// Return `Some((data, err))`, where `data` are the 12 data bits and `err` is the number
/// of errors corrected, on success and `None` on a detected unrecoverable error.
pub fn decode(word: u16) -> Option<(u8, usize)> {
    // Go through a full cycle of the codeword, so the data bits end up in their original
    // position. The word is expanded to 32 bits so it can be treated as the 17-bit word
    // the shortened code is derived from.
    let (fixed, word) = (0..17).fold((Some(0), word as u32), |(fixed, word), _| {
        let syn = syndrome(word);

        if syn == 0 {
            return (fixed, rotate_17(word));
        }

        match pattern(syn) {
            Some(pat) => (Some(pat.count_ones()), rotate_17(word ^ pat)),
            None => (None, rotate_17(word)),
        }
    });

    match fixed {
        Some(err) => Some(((word >> 8) as u8, err as usize)),
        None => None,
    }
}

/// Transposed generator matrix.
const GEN: [u8; 8] = [
    0b00111100,
    0b10011110,
    0b01001111,
    0b00011011,
    0b10110001,
    0b11100100,
    0b11110010,
    0b01111001,
];

/// Transposed parity-check matrix, where the rows of the original are generated from x^i
/// mod g(x).
const PAR: [u32; 8] = [
    0b10000000100111100,
    0b01000000010011110,
    0b00100000001001111,
    0b00010000100011011,
    0b00001000110110001,
    0b00000100111100100,
    0b00000010011110010,
    0b00000001001111001,
];

/// Calculate the syndrome of the given word.
fn syndrome(word: u32) -> u8 {
    matrix_mul!(word, PAR, u8)
}

/// Find the error pattern associated with the syndrome.
///
/// One of the benefits of the cyclic algorithm is we only have to store error patterns
/// with the LSB set.
fn pattern(syn: u8) -> Option<u32> {
    match syn {
        0b00011001 => Some(0b00100000000000001),
        0b00011110 => Some(0b00000000001000001),
        0b00101001 => Some(0b00010000000000001),
        0b00110001 => Some(0b00001000000000001),
        0b00111000 => Some(0b00000001000000001),
        0b00111001 => Some(0b00000000000000001),
        0b00111011 => Some(0b00000010000000001),
        0b00111101 => Some(0b00000100000000001),
        0b01001011 => Some(0b00000000000000011),
        0b01110111 => Some(0b00000000010000001),
        0b01111001 => Some(0b01000000000000001),
        0b10100101 => Some(0b00000000100000001),
        0b10110110 => Some(0b00000000000100001),
        0b10111001 => Some(0b10000000000000001),
        0b11001000 => Some(0b00000000000001001),
        0b11011101 => Some(0b00000000000000101),
        0b11100010 => Some(0b00000000000010001),
        _ => None,
    }
}

/// Cyclically rotate the word as if it was 17 bits long.
fn rotate_17(word: u32) -> u32 {
    let lsb = word & 1;
    word >> 1 | lsb << 16
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_decode() {
        let w = 0b10101011;
        let e = encode(w);

        assert_eq!(Some((w, 0)), decode(e^0b0000000000000000));
        assert_eq!(Some((w, 2)), decode(e^0b1000000000000001));
        assert_eq!(Some((w, 1)), decode(e^0b0001000000000000));
        assert_eq!(Some((w, 2)), decode(e^0b0011000000000000));

        assert_eq!(Some((w, 1)), decode(e^0b1000000000000000));
        assert_eq!(Some((w, 1)), decode(e^0b0100000000000000));
        assert_eq!(Some((w, 2)), decode(e^0b0010000000000001));
        assert_eq!(Some((w, 2)), decode(e^0b0001000000000010));
        assert_eq!(Some((w, 2)), decode(e^0b0000100000000100));
        assert_eq!(Some((w, 2)), decode(e^0b0000010000001000));
        assert_eq!(Some((w, 2)), decode(e^0b0000001000010000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000100100000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000011000000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000001010000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000010001000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000100000100));
        assert_eq!(Some((w, 2)), decode(e^0b0000001000000010));
        assert_eq!(Some((w, 2)), decode(e^0b0000010000000001));
        assert_eq!(Some((w, 1)), decode(e^0b0000100000000000));
        assert_eq!(Some((w, 1)), decode(e^0b0001000000000000));
        assert_eq!(Some((w, 2)), decode(e^0b0010000000000001));
        assert_eq!(Some((w, 2)), decode(e^0b0100000000000100));
        assert_eq!(Some((w, 2)), decode(e^0b1000000000001000));

        for i in 0..1u16<<8 {
            assert_eq!(decode(encode(i as u8)).unwrap().0, i as u8);
        }
    }
}
<commit_msg>Remove stub syndrome function<commit_after>//! Encoding and decoding of the (16, 8, 5) shortened cyclic code described by P25.
//!
//! The parity-check matrix construction was sourced from \[1] and the decoding algorithm
//! was derived from \[2]. The key information that this code is shortened from a (17, 8,
//! 5) code came from \[3].
//!
//! \[1]: "Coding Theory and Cryptography: The Essentials", 2nd ed, Hankerson, Hoffman, et
//! al, 2000
//! \[2]: "Error Control Coding", Lin and Costello, 1983
//! \[3]: "Standard APCO25 Physical Layer of the Radio Transmission Chain", Simon, 2014

/// Encode the 8 data bits into a 16-bit codeword.
pub fn encode(data: u8) -> u16 {
    matrix_mul_systematic!(data, GEN, u16)
}

/// Try to decode the 16-bit word to the nearest codeword, correcting up to 2 errors.
/// Return `Some((data, err))`, where `data` are the 12 data bits and `err` is the number
/// of errors corrected, on success and `None` on a detected unrecoverable error.
pub fn decode(word: u16) -> Option<(u8, usize)> {
    // Go through a full cycle of the codeword, so the data bits end up in their original
    // position. The word is expanded to 32 bits so it can be treated as the 17-bit word
    // the shortened code is derived from.
    let (fixed, word) = (0..17).fold((Some(0), word as u32), |(fixed, word), _| {
        let syn = matrix_mul!(word, PAR, u8);

        if syn == 0 {
            return (fixed, rotate_17(word));
        }

        match pattern(syn) {
            Some(pat) => (Some(pat.count_ones()), rotate_17(word ^ pat)),
            None => (None, rotate_17(word)),
        }
    });

    match fixed {
        Some(err) => Some(((word >> 8) as u8, err as usize)),
        None => None,
    }
}

/// Transposed generator matrix.
const GEN: [u8; 8] = [
    0b00111100,
    0b10011110,
    0b01001111,
    0b00011011,
    0b10110001,
    0b11100100,
    0b11110010,
    0b01111001,
];

/// Transposed parity-check matrix, where the rows of the original are generated from x^i
/// mod g(x).
const PAR: [u32; 8] = [
    0b10000000100111100,
    0b01000000010011110,
    0b00100000001001111,
    0b00010000100011011,
    0b00001000110110001,
    0b00000100111100100,
    0b00000010011110010,
    0b00000001001111001,
];

/// Find the error pattern associated with the syndrome.
///
/// One of the benefits of the cyclic algorithm is we only have to store error patterns
/// with the LSB set.
fn pattern(syn: u8) -> Option<u32> {
    match syn {
        0b00011001 => Some(0b00100000000000001),
        0b00011110 => Some(0b00000000001000001),
        0b00101001 => Some(0b00010000000000001),
        0b00110001 => Some(0b00001000000000001),
        0b00111000 => Some(0b00000001000000001),
        0b00111001 => Some(0b00000000000000001),
        0b00111011 => Some(0b00000010000000001),
        0b00111101 => Some(0b00000100000000001),
        0b01001011 => Some(0b00000000000000011),
        0b01110111 => Some(0b00000000010000001),
        0b01111001 => Some(0b01000000000000001),
        0b10100101 => Some(0b00000000100000001),
        0b10110110 => Some(0b00000000000100001),
        0b10111001 => Some(0b10000000000000001),
        0b11001000 => Some(0b00000000000001001),
        0b11011101 => Some(0b00000000000000101),
        0b11100010 => Some(0b00000000000010001),
        _ => None,
    }
}

/// Cyclically rotate the word as if it was 17 bits long.
fn rotate_17(word: u32) -> u32 {
    let lsb = word & 1;
    word >> 1 | lsb << 16
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_decode() {
        let w = 0b10101011;
        let e = encode(w);

        assert_eq!(Some((w, 0)), decode(e^0b0000000000000000));
        assert_eq!(Some((w, 2)), decode(e^0b1000000000000001));
        assert_eq!(Some((w, 1)), decode(e^0b0001000000000000));
        assert_eq!(Some((w, 2)), decode(e^0b0011000000000000));

        assert_eq!(Some((w, 1)), decode(e^0b1000000000000000));
        assert_eq!(Some((w, 1)), decode(e^0b0100000000000000));
        assert_eq!(Some((w, 2)), decode(e^0b0010000000000001));
        assert_eq!(Some((w, 2)), decode(e^0b0001000000000010));
        assert_eq!(Some((w, 2)), decode(e^0b0000100000000100));
        assert_eq!(Some((w, 2)), decode(e^0b0000010000001000));
        assert_eq!(Some((w, 2)), decode(e^0b0000001000010000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000100100000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000011000000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000001010000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000010001000));
        assert_eq!(Some((w, 2)), decode(e^0b0000000100000100));
        assert_eq!(Some((w, 2)), decode(e^0b0000001000000010));
        assert_eq!(Some((w, 2)), decode(e^0b0000010000000001));
        assert_eq!(Some((w, 1)), decode(e^0b0000100000000000));
        assert_eq!(Some((w, 1)), decode(e^0b0001000000000000));
        assert_eq!(Some((w, 2)), decode(e^0b0010000000000001));
        assert_eq!(Some((w, 2)), decode(e^0b0100000000000100));
        assert_eq!(Some((w, 2)), decode(e^0b1000000000001000));

        for i in 0..1u16<<8 {
            assert_eq!(decode(encode(i as u8)).unwrap().0, i as u8);
        }
    }
}
<|endoftext|>


<commit_before>use error::{CliError, Usage, UsageKind};
use super::Command;

extern crate chrono;

use self::chrono::Local;

use error::CannotHappenError;
use lib::fs::*;
use lib::io::*;
use lib::setting;
use std::fs;
use std::io::Error as IoError;
use std::path::PathBuf;

pub struct Sweep;

impl Command for Sweep {
    fn validation(&self) -> bool { true }

    fn usage(&self) -> Usage {
        return Usage::new(UsageKind::Sweep);
    }

    fn main(&self) -> Result<(), CliError> {
        let now  = Local::now();
        let date = now.format("%Y-%m-%d").to_string();

        let path_to_dust_box = path_buf![setting::storage_dir(), date, "dusts"];
        try!(setting::create_essential_dir_all(&path_to_dust_box));

        let ignore = try!(setting::read_ignore_file());

        let target_files = walk_dir(".")
            .difference(&ignore)
            .cloned()
            .collect::<Vec<String>>();
        for target in &target_files {
            try!(Self::move_file_to_dust_box(target, &path_to_dust_box));
        }

        let dirs = dirs_ordered_by_descending_depth(".");
        for target in dirs.iter().filter(|d| *d != "." && is_empty_dir(d)) {
            try!(Self::move_dir_to_dust_box(target, &path_to_dust_box));
        }

        Ok(())
    }
}

impl Sweep {
    fn move_file_to_dust_box(target: &String, path_to_dust_box: &PathBuf) -> Result<(), CliError> {
        let target_path = path_buf![target];
        let target_file = try!(target_path.file_name().ok_or(CannotHappenError));
        let target_base = try!(target_path.parent().ok_or(CannotHappenError));
        let to = path_buf![&path_to_dust_box, target_base];

        let message = format!("Move \"{}\" file to \"{}\" directory", target_path.display(), path_to_dust_box.display());
        print_with_tag(Tag::Info, message);

        try!(setting::create_essential_dir_all(&to));

        // forcedly overwrite if the file exists with same name.
        try!(fs::rename(target, path_buf![to, target_file]));

        Ok(())
    }

    fn move_dir_to_dust_box(target: &String, path_to_dust_box: &PathBuf) -> Result<(), IoError> {
        try!(fs::remove_dir(target));
        try!(setting::create_essential_dir_all(&path_buf![path_to_dust_box, target]));

        Ok(())
    }
}
<commit_msg>[Refactoring] Enough to know the directory is_empty()<commit_after>use error::{CliError, Usage, UsageKind};
use super::Command;

extern crate chrono;

use self::chrono::Local;

use error::CannotHappenError;
use lib::fs::*;
use lib::io::*;
use lib::setting;
use std::fs;
use std::io::Error as IoError;
use std::path::PathBuf;

pub struct Sweep;

impl Command for Sweep {
    fn validation(&self) -> bool { true }

    fn usage(&self) -> Usage {
        return Usage::new(UsageKind::Sweep);
    }

    fn main(&self) -> Result<(), CliError> {
        let now  = Local::now();
        let date = now.format("%Y-%m-%d").to_string();

        let path_to_dust_box = path_buf![setting::storage_dir(), date, "dusts"];
        try!(setting::create_essential_dir_all(&path_to_dust_box));

        let ignore = try!(setting::read_ignore_file());

        let target_files = walk_dir(".")
            .difference(&ignore)
            .cloned()
            .collect::<Vec<String>>();
        for target in &target_files {
            try!(Self::move_file_to_dust_box(target, &path_to_dust_box));
        }

        let dirs = dirs_ordered_by_descending_depth(".");
        for target in dirs.iter().filter(|d| is_empty_dir(d)) {
            try!(Self::move_dir_to_dust_box(target, &path_to_dust_box));
        }

        Ok(())
    }
}

impl Sweep {
    fn move_file_to_dust_box(target: &String, path_to_dust_box: &PathBuf) -> Result<(), CliError> {
        let target_path = path_buf![target];
        let target_file = try!(target_path.file_name().ok_or(CannotHappenError));
        let target_base = try!(target_path.parent().ok_or(CannotHappenError));
        let to = path_buf![&path_to_dust_box, target_base];

        let message = format!("Move \"{}\" file to \"{}\" directory", target_path.display(), path_to_dust_box.display());
        print_with_tag(Tag::Info, message);

        try!(setting::create_essential_dir_all(&to));

        // forcedly overwrite if the file exists with same name.
        try!(fs::rename(target, path_buf![to, target_file]));

        Ok(())
    }

    fn move_dir_to_dust_box(target: &String, path_to_dust_box: &PathBuf) -> Result<(), IoError> {
        try!(fs::remove_dir(target));
        try!(setting::create_essential_dir_all(&path_buf![path_to_dust_box, target]));

        Ok(())
    }
}
<|endoftext|>