<commit_before>import std::io;
import std::str;
import std::option;
import std::fs;
import std::os;
import std::vec;
import std::test;

import common::mode_run_pass;
import common::mode_run_fail;
import common::mode_compile_fail;
import common::mode_pretty;
import common::cx;
import common::config;
import header::load_props;
import header::test_props;
import util::logv;

export run;

fn run(cx: &cx, _testfile: -[u8]) {
    let testfile = str::unsafe_from_bytes(_testfile);
    if cx.config.verbose {
        // We're going to be dumping a lot of info. Start on a new line.
        io::stdout().write_str("\n\n");
    }
    log #fmt["running %s", testfile];
    let props = load_props(testfile);
    alt cx.config.mode {
      mode_compile_fail. { run_cfail_test(cx, props, testfile); }
      mode_run_fail. { run_rfail_test(cx, props, testfile); }
      mode_run_pass. { run_rpass_test(cx, props, testfile); }
      mode_pretty. { run_pretty_test(cx, props, testfile); }
    }
}

fn run_cfail_test(cx: &cx, props: &test_props, testfile: &str) {
    let procres = compile_test(cx, props, testfile);

    if procres.status == 0 {
        fatal_procres("compile-fail test compiled successfully!", procres);
    }

    check_error_patterns(props, testfile, procres);
}

fn run_rfail_test(cx: &cx, props: &test_props, testfile: &str) {
    let procres = compile_test(cx, props, testfile);

    if procres.status != 0 { fatal_procres("compilation failed!", procres); }

    procres = exec_compiled_test(cx, props, testfile);

    if procres.status == 0 {
        fatal_procres("run-fail test didn't produce an error!", procres);
    }

    // This is the value valgrind returns on failure
    // FIXME: Why is this value neither the value we pass to
    // valgrind as --error-exitcode (1), nor the value we see as the
    // exit code on the command-line (137)?
    const valgrind_err: int = 9;
    if procres.status == valgrind_err {
        fatal_procres("run-fail test isn't valgrind-clean!", procres);
    }

    check_error_patterns(props, testfile, procres);
}

fn run_rpass_test(cx: &cx, props: &test_props, testfile: &str) {
    let procres = compile_test(cx, props, testfile);

    if procres.status != 0 { fatal_procres("compilation failed!", procres); }

    procres = exec_compiled_test(cx, props, testfile);

    if procres.status != 0 { fatal_procres("test run failed!", procres); }
}

fn run_pretty_test(cx: &cx, props: &test_props, testfile: &str) {
    if option::is_some(props.pp_exact) {
        logv(cx.config, "testing for exact pretty-printing");
    } else { logv(cx.config, "testing for converging pretty-printing"); }

    let rounds =
        alt props.pp_exact { option::some(_) { 1 } option::none. { 2 } };

    let srcs = [io::read_whole_file_str(testfile)];

    let round = 0;
    while round < rounds {
        logv(cx.config, #fmt["pretty-printing round %d", round]);
        let procres = print_source(cx, testfile, srcs[round]);

        if procres.status != 0 {
            fatal_procres(#fmt["pretty-printing failed in round %d", round],
                          procres);
        }

        srcs += [procres.stdout];
        round += 1;
    }

    let expected =
        alt props.pp_exact {
          option::some(file) {
            let filepath = fs::connect(fs::dirname(testfile), file);
            io::read_whole_file_str(filepath)
          }
          option::none. { srcs[vec::len(srcs) - 2u] }
        };
    let actual = srcs[vec::len(srcs) - 1u];

    if option::is_some(props.pp_exact) {
        // Now we have to care about line endings
        let cr = "\r";
        check (str::is_not_empty(cr));
        actual = str::replace(actual, cr, "");
        expected = str::replace(expected, cr, "");
    }

    compare_source(expected, actual);

    // Finally, let's make sure it actually appears to remain valid code
    let procres = typecheck_source(cx, testfile, actual);

    if procres.status != 0 {
        fatal_procres("pretty-printed source does not typecheck", procres);
    }

    ret;

    fn print_source(cx: &cx, testfile: &str, src: &str) -> procres {
        compose_and_run(cx, testfile, make_pp_args,
                        cx.config.compile_lib_path, option::some(src))
    }

    fn make_pp_args(config: &config, _testfile: &str) -> procargs {
        let prog = config.rustc_path;
        let args = ["-", "--pretty", "normal"];
        ret {prog: prog, args: args};
    }

    fn compare_source(expected: &str, actual: &str) {
        if expected != actual {
            error("pretty-printed source does match expected source");
            let msg =
                #fmt["\n\
expected:\n\
------------------------------------------\n\
%s\n\
------------------------------------------\n\
actual:\n\
------------------------------------------\n\
%s\n\
------------------------------------------\n\
\n",
                     expected, actual];
            io::stdout().write_str(msg);
            fail;
        }
    }

    fn typecheck_source(cx: &cx, testfile: &str, src: &str) -> procres {
        compose_and_run(cx, testfile, make_typecheck_args,
                        cx.config.compile_lib_path, option::some(src))
    }

    fn make_typecheck_args(config: &config, _testfile: &str) -> procargs {
        let prog = config.rustc_path;
        let args = ["-", "--no-trans", "--lib"];
        ret {prog: prog, args: args};
    }
}

fn check_error_patterns(props: &test_props, testfile: &str,
                        procres: &procres) {
    if vec::is_empty(props.error_patterns) {
        fatal("no error pattern specified in " + testfile);
    }

    let next_err_idx = 0u;
    let next_err_pat = props.error_patterns[next_err_idx];
    for line: str in str::split(procres.stdout, '\n' as u8) {
        if str::find(line, next_err_pat) > 0 {
            log #fmt["found error pattern %s", next_err_pat];
            next_err_idx += 1u;
            if next_err_idx == vec::len(props.error_patterns) {
                log "found all error patterns";
                ret;
            }
            next_err_pat = props.error_patterns[next_err_idx];
        }
    }

    let missing_patterns =
        vec::slice(props.error_patterns, next_err_idx,
                   vec::len(props.error_patterns));
    if vec::len(missing_patterns) == 1u {
        fatal_procres(#fmt["error pattern '%s' not found!",
                           missing_patterns[0]], procres);
    } else {
        for pattern: str in missing_patterns {
            error(#fmt["error pattern '%s' not found!", pattern]);
        }
        fatal_procres("multiple error patterns not found", procres);
    }
}

type procargs = {prog: str, args: [str]};

type procres = {status: int, stdout: str, stderr: str, cmdline: str};

fn compile_test(cx: &cx, props: &test_props, testfile: &str) -> procres {
    compose_and_run(cx, testfile, bind make_compile_args(_, props, _),
                    cx.config.compile_lib_path, option::none)
}

fn exec_compiled_test(cx: &cx, props: &test_props, testfile: &str) ->
   procres {
    compose_and_run(cx, testfile, bind make_run_args(_, props, _),
                    cx.config.run_lib_path, option::none)
}

fn compose_and_run(cx: &cx, testfile: &str,
                   make_args: fn(&config, &str) -> procargs, lib_path: &str,
                   input: option::t<str>) -> procres {
    let procargs = make_args(cx.config, testfile);
    ret program_output(cx, testfile, lib_path, procargs.prog, procargs.args,
                       input);
}

fn make_compile_args(config: &config, props: &test_props, testfile: &str) ->
   procargs {
    let prog = config.rustc_path;
    let args = [testfile, "-o", make_exe_name(config, testfile)];
    args += split_maybe_args(config.rustcflags);
    args += split_maybe_args(props.compile_flags);
    ret {prog: prog, args: args};
}

fn make_exe_name(config: &config, testfile: &str) -> str {
    output_base_name(config, testfile) + os::exec_suffix()
}

fn make_run_args(config: &config, props: &test_props, testfile: &str) ->
   procargs {
    let toolargs =
        if !props.no_valgrind {

            // If we've got another tool to run under (valgrind),
            // then split apart its command
            split_maybe_args(config.runtool)
        } else { [] };

    let args = toolargs + [make_exe_name(config, testfile)];
    ret {prog: args[0], args: vec::slice(args, 1u, vec::len(args))};
}

fn split_maybe_args(argstr: &option::t<str>) -> [str] {
    fn rm_whitespace(v: &[str]) -> [str] {
        fn flt(s: &str) -> option::t<str> {
            if !is_whitespace(s) { option::some(s) } else { option::none }
        }

        // FIXME: This should be in std
        fn is_whitespace(s: str) -> bool {
            for c: u8 in s { if c != ' ' as u8 { ret false; } }
            ret true;
        }
        vec::filter_map(flt, v)
    }

    alt argstr {
      option::some(s) { rm_whitespace(str::split(s, ' ' as u8)) }
      option::none. { [] }
    }
}

fn program_output(cx: &cx, testfile: &str, lib_path: &str, prog: &str,
                  args: &[str], input: option::t<str>) -> procres {
    let cmdline =
        {
            let cmdline = make_cmdline(lib_path, prog, args);
            logv(cx.config, #fmt["executing %s", cmdline]);
            cmdline
        };
    let res = procsrv::run(cx.procsrv, lib_path, prog, args, input);
    dump_output(cx.config, testfile, res.out, res.err);
    ret {status: res.status,
         stdout: res.out,
         stderr: res.err,
         cmdline: cmdline};
}

fn make_cmdline(libpath: &str, prog: &str, args: &[str]) -> str {
    #fmt["%s %s %s", lib_path_cmd_prefix(libpath), prog,
         str::connect(args, " ")]
}

// Build the LD_LIBRARY_PATH variable as it would be seen on the command line
// for diagnostic purposes
fn lib_path_cmd_prefix(path: &str) -> str {
    #fmt["%s=\"%s\"", util::lib_path_env_var(), util::make_new_path(path)]
}

fn dump_output(config: &config, testfile: &str, out: &str, err: &str) {
    dump_output_file(config, testfile, out, "out");
    dump_output_file(config, testfile, err, "err");
    maybe_dump_to_stdout(config, out, err);
}

#[cfg(target_os = "win32")]
#[cfg(target_os = "linux")]
fn dump_output_file(config: &config, testfile: &str, out: &str,
                    extension: &str) {
    let outfile = make_out_name(config, testfile, extension);
    let writer = io::file_writer(outfile, [io::create, io::truncate]);
    writer.write_str(out);
}

// FIXME (726): Can't use file_writer on mac
#[cfg(target_os = "macos")]
fn dump_output_file(config: &config, testfile: &str, out: &str,
                    extension: &str) {
}

fn make_out_name(config: &config, testfile: &str, extension: &str) -> str {
    output_base_name(config, testfile) + "." + extension
}

fn output_base_name(config: &config, testfile: &str) -> str {
    let base = config.build_base;
    let filename =
        {
            let parts = str::split(fs::basename(testfile), '.' as u8);
            parts = vec::slice(parts, 0u, vec::len(parts) - 1u);
            str::connect(parts, ".")
        };
    #fmt["%s%s.%s", base, filename, config.stage_id]
}

fn maybe_dump_to_stdout(config: &config, out: &str, err: &str) {
    if config.verbose {
        let sep1 = #fmt["------%s------------------------------", "stdout"];
        let sep2 = #fmt["------%s------------------------------", "stderr"];
        let sep3 = "------------------------------------------";
        io::stdout().write_line(sep1);
        io::stdout().write_line(out);
        io::stdout().write_line(sep2);
        io::stdout().write_line(err);
        io::stdout().write_line(sep3);
    }
}

fn error(err: &str) { io::stdout().write_line(#fmt["\nerror: %s", err]); }

fn fatal(err: &str) -> ! { error(err); fail; }

fn fatal_procres(err: &str, procres: procres) -> ! {
    let msg =
        #fmt["\n\
error: %s\n\
command: %s\n\
stdout:\n\
------------------------------------------\n\
%s\n\
------------------------------------------\n\
stderr:\n\
------------------------------------------\n\
%s\n\
------------------------------------------\n\
\n",
             err, procres.cmdline, procres.stdout, procres.stderr];
    io::stdout().write_str(msg);
    fail;
}
<commit_msg>Test that processes that are supposed to fail return a non-zero status<commit_after>import std::io;
import std::str;
import std::option;
import std::fs;
import std::os;
import std::vec;
import std::test;

import common::mode_run_pass;
import common::mode_run_fail;
import common::mode_compile_fail;
import common::mode_pretty;
import common::cx;
import common::config;
import header::load_props;
import header::test_props;
import util::logv;

export run;

fn run(cx: &cx, _testfile: -[u8]) {
    let testfile = str::unsafe_from_bytes(_testfile);
    if cx.config.verbose {
        // We're going to be dumping a lot of info. Start on a new line.
        io::stdout().write_str("\n\n");
    }
    log #fmt["running %s", testfile];
    let props = load_props(testfile);
    alt cx.config.mode {
      mode_compile_fail. { run_cfail_test(cx, props, testfile); }
      mode_run_fail. { run_rfail_test(cx, props, testfile); }
      mode_run_pass. { run_rpass_test(cx, props, testfile); }
      mode_pretty. { run_pretty_test(cx, props, testfile); }
    }
}

fn run_cfail_test(cx: &cx, props: &test_props, testfile: &str) {
    let procres = compile_test(cx, props, testfile);

    if procres.status == 0 {
        fatal_procres("compile-fail test compiled successfully!", procres);
    }

    check_error_patterns(props, testfile, procres);
}

fn run_rfail_test(cx: &cx, props: &test_props, testfile: &str) {
    let procres = compile_test(cx, props, testfile);

    if procres.status != 0 { fatal_procres("compilation failed!", procres); }

    procres = exec_compiled_test(cx, props, testfile);

    if procres.status == 0 {
        fatal_procres("run-fail test didn't produce an error!", procres);
    }

    // This is the value valgrind returns on failure
    // FIXME: Why is this value neither the value we pass to
    // valgrind as --error-exitcode (1), nor the value we see as the
    // exit code on the command-line (137)?
    const valgrind_err: int = 9;
    if procres.status == valgrind_err {
        fatal_procres("run-fail test isn't valgrind-clean!", procres);
    }

    check_error_patterns(props, testfile, procres);
}

fn run_rpass_test(cx: &cx, props: &test_props, testfile: &str) {
    let procres = compile_test(cx, props, testfile);

    if procres.status != 0 { fatal_procres("compilation failed!", procres); }

    procres = exec_compiled_test(cx, props, testfile);

    if procres.status != 0 { fatal_procres("test run failed!", procres); }
}

fn run_pretty_test(cx: &cx, props: &test_props, testfile: &str) {
    if option::is_some(props.pp_exact) {
        logv(cx.config, "testing for exact pretty-printing");
    } else { logv(cx.config, "testing for converging pretty-printing"); }

    let rounds =
        alt props.pp_exact { option::some(_) { 1 } option::none. { 2 } };

    let srcs = [io::read_whole_file_str(testfile)];

    let round = 0;
    while round < rounds {
        logv(cx.config, #fmt["pretty-printing round %d", round]);
        let procres = print_source(cx, testfile, srcs[round]);

        if procres.status != 0 {
            fatal_procres(#fmt["pretty-printing failed in round %d", round],
                          procres);
        }

        srcs += [procres.stdout];
        round += 1;
    }

    let expected =
        alt props.pp_exact {
          option::some(file) {
            let filepath = fs::connect(fs::dirname(testfile), file);
            io::read_whole_file_str(filepath)
          }
          option::none. { srcs[vec::len(srcs) - 2u] }
        };
    let actual = srcs[vec::len(srcs) - 1u];

    if option::is_some(props.pp_exact) {
        // Now we have to care about line endings
        let cr = "\r";
        check (str::is_not_empty(cr));
        actual = str::replace(actual, cr, "");
        expected = str::replace(expected, cr, "");
    }

    compare_source(expected, actual);

    // Finally, let's make sure it actually appears to remain valid code
    let procres = typecheck_source(cx, testfile, actual);

    if procres.status != 0 {
        fatal_procres("pretty-printed source does not typecheck", procres);
    }

    ret;

    fn print_source(cx: &cx, testfile: &str, src: &str) -> procres {
        compose_and_run(cx, testfile, make_pp_args,
                        cx.config.compile_lib_path, option::some(src))
    }

    fn make_pp_args(config: &config, _testfile: &str) -> procargs {
        let prog = config.rustc_path;
        let args = ["-", "--pretty", "normal"];
        ret {prog: prog, args: args};
    }

    fn compare_source(expected: &str, actual: &str) {
        if expected != actual {
            error("pretty-printed source does match expected source");
            let msg =
                #fmt["\n\
expected:\n\
------------------------------------------\n\
%s\n\
------------------------------------------\n\
actual:\n\
------------------------------------------\n\
%s\n\
------------------------------------------\n\
\n",
                     expected, actual];
            io::stdout().write_str(msg);
            fail;
        }
    }

    fn typecheck_source(cx: &cx, testfile: &str, src: &str) -> procres {
        compose_and_run(cx, testfile, make_typecheck_args,
                        cx.config.compile_lib_path, option::some(src))
    }

    fn make_typecheck_args(config: &config, _testfile: &str) -> procargs {
        let prog = config.rustc_path;
        let args = ["-", "--no-trans", "--lib"];
        ret {prog: prog, args: args};
    }
}

fn check_error_patterns(props: &test_props, testfile: &str,
                        procres: &procres) {
    if vec::is_empty(props.error_patterns) {
        fatal("no error pattern specified in " + testfile);
    }

    if procres.status == 0 {
        fatal("process did not return an error status");
    }

    let next_err_idx = 0u;
    let next_err_pat = props.error_patterns[next_err_idx];
    for line: str in str::split(procres.stdout, '\n' as u8) {
        if str::find(line, next_err_pat) > 0 {
            log #fmt["found error pattern %s", next_err_pat];
            next_err_idx += 1u;
            if next_err_idx == vec::len(props.error_patterns) {
                log "found all error patterns";
                ret;
            }
            next_err_pat = props.error_patterns[next_err_idx];
        }
    }

    let missing_patterns =
        vec::slice(props.error_patterns, next_err_idx,
                   vec::len(props.error_patterns));
    if vec::len(missing_patterns) == 1u {
        fatal_procres(#fmt["error pattern '%s' not found!",
                           missing_patterns[0]], procres);
    } else {
        for pattern: str in missing_patterns {
            error(#fmt["error pattern '%s' not found!", pattern]);
        }
        fatal_procres("multiple error patterns not found", procres);
    }
}

type procargs = {prog: str, args: [str]};

type procres = {status: int, stdout: str, stderr: str, cmdline: str};

fn compile_test(cx: &cx, props: &test_props, testfile: &str) -> procres {
    compose_and_run(cx, testfile, bind make_compile_args(_, props, _),
                    cx.config.compile_lib_path, option::none)
}

fn exec_compiled_test(cx: &cx, props: &test_props, testfile: &str) ->
   procres {
    compose_and_run(cx, testfile, bind make_run_args(_, props, _),
                    cx.config.run_lib_path, option::none)
}

fn compose_and_run(cx: &cx, testfile: &str,
                   make_args: fn(&config, &str) -> procargs, lib_path: &str,
                   input: option::t<str>) -> procres {
    let procargs = make_args(cx.config, testfile);
    ret program_output(cx, testfile, lib_path, procargs.prog, procargs.args,
                       input);
}

fn make_compile_args(config: &config, props: &test_props, testfile: &str) ->
   procargs {
    let prog = config.rustc_path;
    let args = [testfile, "-o", make_exe_name(config, testfile)];
    args += split_maybe_args(config.rustcflags);
    args += split_maybe_args(props.compile_flags);
    ret {prog: prog, args: args};
}

fn make_exe_name(config: &config, testfile: &str) -> str {
    output_base_name(config, testfile) + os::exec_suffix()
}

fn make_run_args(config: &config, props: &test_props, testfile: &str) ->
   procargs {
    let toolargs =
        if !props.no_valgrind {

            // If we've got another tool to run under (valgrind),
            // then split apart its command
            split_maybe_args(config.runtool)
        } else { [] };

    let args = toolargs + [make_exe_name(config, testfile)];
    ret {prog: args[0], args: vec::slice(args, 1u, vec::len(args))};
}

fn split_maybe_args(argstr: &option::t<str>) -> [str] {
    fn rm_whitespace(v: &[str]) -> [str] {
        fn flt(s: &str) -> option::t<str> {
            if !is_whitespace(s) { option::some(s) } else { option::none }
        }

        // FIXME: This should be in std
        fn is_whitespace(s: str) -> bool {
            for c: u8 in s { if c != ' ' as u8 { ret false; } }
            ret true;
        }
        vec::filter_map(flt, v)
    }

    alt argstr {
      option::some(s) { rm_whitespace(str::split(s, ' ' as u8)) }
      option::none. { [] }
    }
}

fn program_output(cx: &cx, testfile: &str, lib_path: &str, prog: &str,
                  args: &[str], input: option::t<str>) -> procres {
    let cmdline =
        {
            let cmdline = make_cmdline(lib_path, prog, args);
            logv(cx.config, #fmt["executing %s", cmdline]);
            cmdline
        };
    let res = procsrv::run(cx.procsrv, lib_path, prog, args, input);
    dump_output(cx.config, testfile, res.out, res.err);
    ret {status: res.status,
         stdout: res.out,
         stderr: res.err,
         cmdline: cmdline};
}

fn make_cmdline(libpath: &str, prog: &str, args: &[str]) -> str {
    #fmt["%s %s %s", lib_path_cmd_prefix(libpath), prog,
         str::connect(args, " ")]
}

// Build the LD_LIBRARY_PATH variable as it would be seen on the command line
// for diagnostic purposes
fn lib_path_cmd_prefix(path: &str) -> str {
    #fmt["%s=\"%s\"", util::lib_path_env_var(), util::make_new_path(path)]
}

fn dump_output(config: &config, testfile: &str, out: &str, err: &str) {
    dump_output_file(config, testfile, out, "out");
    dump_output_file(config, testfile, err, "err");
    maybe_dump_to_stdout(config, out, err);
}

#[cfg(target_os = "win32")]
#[cfg(target_os = "linux")]
fn dump_output_file(config: &config, testfile: &str, out: &str,
                    extension: &str) {
    let outfile = make_out_name(config, testfile, extension);
    let writer = io::file_writer(outfile, [io::create, io::truncate]);
    writer.write_str(out);
}

// FIXME (726): Can't use file_writer on mac
#[cfg(target_os = "macos")]
fn dump_output_file(config: &config, testfile: &str, out: &str,
                    extension: &str) {
}

fn make_out_name(config: &config, testfile: &str, extension: &str) -> str {
    output_base_name(config, testfile) + "." + extension
}

fn output_base_name(config: &config, testfile: &str) -> str {
    let base = config.build_base;
    let filename =
        {
            let parts = str::split(fs::basename(testfile), '.' as u8);
            parts = vec::slice(parts, 0u, vec::len(parts) - 1u);
            str::connect(parts, ".")
        };
    #fmt["%s%s.%s", base, filename, config.stage_id]
}

fn maybe_dump_to_stdout(config: &config, out: &str, err: &str) {
    if config.verbose {
        let sep1 = #fmt["------%s------------------------------", "stdout"];
        let sep2 = #fmt["------%s------------------------------", "stderr"];
        let sep3 = "------------------------------------------";
        io::stdout().write_line(sep1);
        io::stdout().write_line(out);
        io::stdout().write_line(sep2);
        io::stdout().write_line(err);
        io::stdout().write_line(sep3);
    }
}

fn error(err: &str) { io::stdout().write_line(#fmt["\nerror: %s", err]); }

fn fatal(err: &str) -> ! { error(err); fail; }

fn fatal_procres(err: &str, procres: procres) -> ! {
    let msg =
        #fmt["\n\
error: %s\n\
command: %s\n\
stdout:\n\
------------------------------------------\n\
%s\n\
------------------------------------------\n\
stderr:\n\
------------------------------------------\n\
%s\n\
------------------------------------------\n\
\n",
             err, procres.cmdline, procres.stdout, procres.stderr];
    io::stdout().write_str(msg);
    fail;
}
<|endoftext|>


<commit_before>use ordered_float::NotNaN;

use itertools::Itertools;
use bio::stats::probs::cdf::CDF;
use bio::stats::probs::cdf;

use model;

#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub struct MeanVar {
    pub mean: NotNaN<f64>,
    pub var: NotNaN<f64>
}

impl MeanVar {

    pub fn standard_deviation(&self) -> f64 {
        self.var.sqrt()
    }

    pub fn coefficient_of_variation(&self) -> f64 {
        self.standard_deviation() / *self.mean
    }
}

pub fn cdf<T: Ord, F: Fn(NotNaN<f64>, NotNaN<f64>) -> T>(cdfs: &[CDF<NotNaN<f64>>], value: F) -> CDF<T> {
    let n = cdfs.len() as f64;
    let mut curr = Vec::new();
    let mut prev = {
        let mut pmf = Vec::new();
        for e in cdfs[0].iter_pmf() {
            pmf.push(cdf::Entry {
                value: (*e.value, NotNaN::new(0.0).unwrap()),
                prob: e.prob
            });
        }
        CDF::from_pmf(pmf)
    };

    for (k, cdf) in cdfs.iter().enumerate().skip(1) {
        assert_relative_eq!(cdf.total_prob().exp(), 1.0, epsilon=0.002);

        let k = k as f64 + 1.0;

        for prev_entry in prev.sample(1000).iter_pmf() {
            let &(m, s) = prev_entry.value;
            for e in cdf.iter_pmf() {
                let p = prev_entry.prob + e.prob;
                let mk = m + (*e.value - m) / k;
                let sk = s + (*e.value - m) * (*e.value - mk);
                curr.push(cdf::Entry { value: (mk, sk), prob: p });
            }
        }
        prev = CDF::from_pmf(curr);
        curr = Vec::new();
    }
    let pmf = prev.iter_pmf().map(|e| {
        let &(m, s) = e.value;
        cdf::Entry{ value: value(m, s / (n - 1.0)), prob: e.prob }
    }).collect_vec();
    CDF::from_pmf(pmf)
}

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

    use bio::stats::LogProb;

    #[test]
    fn test_cdf() {
        let cdf1 = CDF::from_pmf(vec![
            cdf::Entry{ value: NotNaN::new(6.0).unwrap(), prob: LogProb(-1.0) },
            cdf::Entry { value: NotNaN::new(70.0).unwrap(), prob: LogProb(-0.45867514538708193) }
            ]);
        let cdf2 = CDF::from_pmf(vec![
            cdf::Entry { value: NotNaN::new(3.0).unwrap(), prob: LogProb(-1.0)},
            cdf::Entry { value: NotNaN::new(70.0).unwrap(), prob: LogProb(-0.45867514538708193)}
        ]);
        let cdf3 = CDF::from_pmf(vec![
            cdf::Entry { value: NotNaN::new(3.0).unwrap(), prob: LogProb(-1.0)},
            cdf::Entry { value: NotNaN::new(70.0).unwrap(), prob: LogProb(-0.45867514538708193)}
        ]);
        println!("{}", cdf1.map().unwrap());
        println!("{}", cdf2.map().unwrap());

        let cdf = cdf(&[cdf1, cdf2, cdf3], |mean, _| mean);

        println!("{:?}", cdf);
        println!("{}", cdf.map().unwrap());
        assert_eq!(**cdf.map().unwrap(), 70.0);
    }
}
<commit_msg>Debugging.<commit_after>use ordered_float::NotNaN;

use itertools::Itertools;
use bio::stats::probs::cdf::CDF;
use bio::stats::probs::cdf;

use model;

#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub struct MeanVar {
    pub mean: NotNaN<f64>,
    pub var: NotNaN<f64>
}

impl MeanVar {

    pub fn standard_deviation(&self) -> f64 {
        self.var.sqrt()
    }

    pub fn coefficient_of_variation(&self) -> f64 {
        self.standard_deviation() / *self.mean
    }
}

pub fn cdf<T: Ord, F: Fn(NotNaN<f64>, NotNaN<f64>) -> T>(cdfs: &[CDF<NotNaN<f64>>], value: F) -> CDF<T> {
    let n = cdfs.len() as f64;
    let mut curr = Vec::new();
    let mut prev = {
        let mut pmf = Vec::new();
        for e in cdfs[0].iter_pmf() {
            pmf.push(cdf::Entry {
                value: (*e.value, NotNaN::new(0.0).unwrap()),
                prob: e.prob
            });
        }
        CDF::from_pmf(pmf)
    };

    for (k, cdf) in cdfs.iter().enumerate().skip(1) {
        assert_relative_eq!(cdf.total_prob().exp(), 1.0, epsilon=0.002);

        let k = k as f64 + 1.0;

        for prev_entry in prev.sample(1000).iter_pmf() {
            let &(m, s) = prev_entry.value;
            for e in cdf.iter_pmf() {
                let p = prev_entry.prob + e.prob;
                let mk = m + (*e.value - m) / k;
                let sk = s + (*e.value - m) * (*e.value - mk);
                curr.push(cdf::Entry { value: (mk, sk), prob: p });
            }
        }
        println!("----------\n{:?}", &curr[..5]);
        prev = CDF::from_pmf(curr);
        curr = Vec::new();
    }
    let pmf = prev.iter_pmf().map(|e| {
        let &(m, s) = e.value;
        cdf::Entry{ value: value(m, s / (n - 1.0)), prob: e.prob }
    }).collect_vec();
    CDF::from_pmf(pmf)
}

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

    use bio::stats::LogProb;

    #[test]
    fn test_cdf() {
        let cdf1 = CDF::from_pmf(vec![
            cdf::Entry{ value: NotNaN::new(6.0).unwrap(), prob: LogProb(-1.0) },
            cdf::Entry { value: NotNaN::new(70.0).unwrap(), prob: LogProb(-0.45867514538708193) }
            ]);
        let cdf2 = CDF::from_pmf(vec![
            cdf::Entry { value: NotNaN::new(3.0).unwrap(), prob: LogProb(-1.0)},
            cdf::Entry { value: NotNaN::new(70.0).unwrap(), prob: LogProb(-0.45867514538708193)}
        ]);
        let cdf3 = CDF::from_pmf(vec![
            cdf::Entry { value: NotNaN::new(3.0).unwrap(), prob: LogProb(-1.0)},
            cdf::Entry { value: NotNaN::new(70.0).unwrap(), prob: LogProb(-0.45867514538708193)}
        ]);
        println!("{}", cdf1.map().unwrap());
        println!("{}", cdf2.map().unwrap());

        let cdf = cdf(&[cdf1, cdf2, cdf3], |mean, _| mean);

        println!("{:?}", cdf);
        println!("{}", cdf.map().unwrap());
        assert_eq!(**cdf.map().unwrap(), 70.0);
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-linux see joyent/libuv#1189
// ignore-fast
// ignore-android needs extra network permissions
// exec-env:RUST_LOG=debug

use std::libc;
use std::io::net::ip::{Ipv4Addr, SocketAddr};
use std::io::net::tcp::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};

fn main() {
    // This test has a chance to time out, try to not let it time out
    spawn(proc() {
        use std::io::timer;
        timer::sleep(30 * 1000);
        println!("timed out!");
        unsafe { libc::exit(1) }
    });

    let addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 0 };
    let (tx, rx) = channel();
    spawn(proc() {
        let mut listener = TcpListener::bind(addr).unwrap();
        tx.send(listener.socket_name().unwrap());
        let mut acceptor = listener.listen();
        loop {
            let mut stream = match acceptor.accept() {
                Ok(stream) => stream,
                Err(error) => {
                    debug!("accept failed: {:?}", error);
                    continue;
                }
            };
            stream.read_byte();
            stream.write([2]);
        }
    });
    let addr = rx.recv();

    let (tx, rx) = channel();
    for _ in range(0, 1000) {
        let tx = tx.clone();
        spawn(proc() {
            match TcpStream::connect(addr) {
                Ok(stream) => {
                    let mut stream = stream;
                    stream.write([1]);
                    let mut buf = [0];
                    stream.read(buf);
                },
                Err(e) => debug!("{:?}", e)
            }
            tx.send(());
        });
    }

    // Wait for all clients to exit, but don't wait for the server to exit. The
    // server just runs infinitely.
    drop(tx);
    for _ in range(0, 1000) {
        rx.recv();
    }
    unsafe { libc::exit(0) }
}
<commit_msg>auto merge of #12933 : edwardw/rust/fallout, r=huonw<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-linux see joyent/libuv#1189
// ignore-fast
// ignore-android needs extra network permissions
// exec-env:RUST_LOG=debug

#[feature(phase)];
#[phase(syntax, link)]
extern crate log;

use std::libc;
use std::io::net::ip::{Ipv4Addr, SocketAddr};
use std::io::net::tcp::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};

fn main() {
    // This test has a chance to time out, try to not let it time out
    spawn(proc() {
        use std::io::timer;
        timer::sleep(30 * 1000);
        println!("timed out!");
        unsafe { libc::exit(1) }
    });

    let addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 0 };
    let (tx, rx) = channel();
    spawn(proc() {
        let mut listener = TcpListener::bind(addr).unwrap();
        tx.send(listener.socket_name().unwrap());
        let mut acceptor = listener.listen();
        loop {
            let mut stream = match acceptor.accept() {
                Ok(stream) => stream,
                Err(error) => {
                    debug!("accept failed: {:?}", error);
                    continue;
                }
            };
            stream.read_byte();
            stream.write([2]);
        }
    });
    let addr = rx.recv();

    let (tx, rx) = channel();
    for _ in range(0, 1000) {
        let tx = tx.clone();
        spawn(proc() {
            match TcpStream::connect(addr) {
                Ok(stream) => {
                    let mut stream = stream;
                    stream.write([1]);
                    let mut buf = [0];
                    stream.read(buf);
                },
                Err(e) => debug!("{:?}", e)
            }
            tx.send(());
        });
    }

    // Wait for all clients to exit, but don't wait for the server to exit. The
    // server just runs infinitely.
    drop(tx);
    for _ in range(0, 1000) {
        rx.recv();
    }
    unsafe { libc::exit(0) }
}
<|endoftext|>


<commit_before>// ignore-tidy-linelength

#![crate_name = "foo"]

//! This is the "start" of the 'document'! How'd you know that "it's" the start?
//!
//! # Header with "smart punct'"
//!
//! [link with "smart punct'" -- yessiree!][]
//!
//! [link with "smart punct'" -- yessiree!]: https://www.rust-lang.org
//!
//! # Code should not be smart-punct'd
//!
//! `this inline code -- it shouldn't have "smart punct"`
//!
//! ```
//! let x = "don't smart-punct me -- please!";
//! ```
//!
//! ```text
//! I say "don't smart-punct me -- please!"
//! ```

// @has "foo/index.html" "//p" "This is the “start” of the ‘document’! How’d you know that “it’s” the start?"
// @has "foo/index.html" "//h1" "Header with “smart punct’”"
// @has "foo/index.html" '//a[@href="https://www.rust-lang.org"]' "link with “smart punct’” – yessiree!"
// @has "foo/index.html" '//code' 'this inline code -- it shouldn\'t have "smart punct"'
// @has "foo/index.html" '//pre' 'let x = "don\'t smart-punct me -- please!";'
// @has "foo/index.html" '//pre' 'I say "don\'t smart-punct me -- please!"'
<commit_msg>Fix `@has` checks "no closing quotation" error<commit_after>// ignore-tidy-linelength

#![crate_name = "foo"]

//! This is the "start" of the 'document'! How'd you know that "it's" the start?
//!
//! # Header with "smart punct'"
//!
//! [link with "smart punct'" -- yessiree!][]
//!
//! [link with "smart punct'" -- yessiree!]: https://www.rust-lang.org
//!
//! # Code should not be smart-punct'd
//!
//! `this inline code -- it shouldn't have "smart punct"`
//!
//! ```
//! let x = "don't smart-punct me -- please!";
//! ```
//!
//! ```text
//! I say "don't smart-punct me -- please!"
//! ```

// @has "foo/index.html" "//p" "This is the “start” of the ‘document’! How’d you know that “it’s” the start?"
// @has "foo/index.html" "//h1" "Header with “smart punct’”"
// @has "foo/index.html" '//a[@href="https://www.rust-lang.org"]' "link with “smart punct’” – yessiree!"
// @has "foo/index.html" '//code' "this inline code -- it shouldn't have \"smart punct\""
// @has "foo/index.html" '//pre' "let x = \"don't smart-punct me -- please!\";"
// @has "foo/index.html" '//pre' "I say \"don't smart-punct me -- please!\""
<|endoftext|>


<commit_before>use config::{Config, OutputFormat};
use net::{curl_json, HttpVerb};
use utils::console::*;
use utils::output;

use clap::{App, Arg, ArgMatches, SubCommand};
use serde_json;
use std::str;
use webbrowser;

pub const NAME: &'static str = "status";

error_chain! {
    errors {
       CenterDeviceStatusFailed {
            description("failed to get CenterDevice status")
            display("failed to get CenterDevice status")
        }
    }
}

#[derive(Deserialize, Debug)]
enum Status {
    Okay,
    Warning,
    Failed,
}

#[allow(non_snake_case)]
#[derive(Deserialize, Debug)]
struct Rest {
    Status: Status,
    Timestamp: String,
    NotificationQueueClientPool: bool,
    FolderHealthCheckSensor: bool,
    DocumentQueueClientPool: bool,
    MetadataStoreResource: bool,
    NotificationStoreResource: bool,
    SearchEngineResource: bool,
    SecurityDataStoreResource: bool,
    SendEmailQueueClientPool: bool,
    UserdataStoreResource: bool,
}

#[allow(non_snake_case)]
#[derive(Deserialize, Debug)]
struct Auth {
    Status: Status,
    Timestamp: String,
    AuthServer: bool,
}

#[allow(non_snake_case)]
#[derive(Deserialize, Debug)]
struct WebClient {
    Status: Status,
    Timestamp: String,
    NotificationAlertingService: bool,
    RestServerSensor: bool,
}

#[allow(non_snake_case)]
#[derive(Deserialize, Debug)]
struct PublicLink {
    Status: Status,
    Timestamp: String,
    PublicLinkClient: bool,
}

#[allow(non_snake_case)]
#[derive(Deserialize, Debug)]
struct DistributorConsole {
    Status: Status,
    Timestamp: String,
    RestServerSensor: bool,
}

#[allow(non_camel_case_types)]
#[derive(Deserialize, Debug)]
enum PingDomStatus {
    up,
    down,
}

#[derive(Deserialize, Debug)]
struct Checks {
    checks: Vec<Vec<Check>>,
}

#[derive(Deserialize, Debug)]
struct Check {
    hostname: String,
    status: PingDomStatus,
    lasttesttime: String,
}

#[allow(non_snake_case)]
#[derive(Deserialize, Debug)]
struct PingDom {
    Status: Status,
    Timestamp: String,
    Checks: Checks,
}

#[allow(non_snake_case)]
#[derive(Deserialize, Debug)]
struct CenterDeviceStatus {
    Status: Status,
    Rest: Rest,
    Auth: Auth,
    WebClient: WebClient,
    PublicLink: PublicLink,
    DistributorConsole: DistributorConsole,
    PingDom: PingDom,
}

pub fn build_sub_cli() -> App<'static, 'static> {
    SubCommand::with_name(NAME)
        .about("Gets public centerdevice status from status server")
        .arg(Arg::with_name("details")
            .long("details")
            .help("Show detailed output"))
        .arg(Arg::with_name("browser")
            .long("browser")
            .help("Open status in web browser"))
}

pub fn call(args: Option<&ArgMatches>, config: &Config) -> Result<()> {
    let details = args.ok_or(false).unwrap().is_present("details");
    let browser = args.ok_or(false).unwrap().is_present("browser");

    if browser {
        info("Opening CenterDevice Status in default browser ...");
        browse(config, details).chain_err(|| ErrorKind::CenterDeviceStatusFailed)
    } else {
        info("Getting CenterDevice Status ...");
        status(config, details).chain_err(|| ErrorKind::CenterDeviceStatusFailed)
    }
}

fn browse(config: &Config, details: bool) -> Result<()> {
    if details {
        webbrowser::open("http://status.centerdevice.de/details.html")
    } else {
        webbrowser::open("http://status.centerdevice.de")
    }.chain_err(|| "Failed to open default browser")?;

    if config.general.output_format == OutputFormat::JSON { msgln("{}"); }

    Ok(())
}

fn status(config: &Config, details: bool) -> Result<()> {
    let json = get_centerdevice_status_json()?;
    output(&json, &config.general.output_format, details)
}

fn get_centerdevice_status_json() -> Result<String> {
    let mut buffer = Vec::new();
    let url = "http://status.centerdevice.de/details.json";

    curl_json(url, HttpVerb::GET, None, None, Some(&mut buffer))
        .chain_err(|| ErrorKind::CenterDeviceStatusFailed)?;
    let json = str::from_utf8(&buffer).chain_err(|| "Data copying failed.")?;

    Ok(json.to_string())
}

fn output(json: &str, format: &OutputFormat, details: bool) -> Result<()> {
    match *format {
        OutputFormat::HUMAN => output_human(json, details),
        OutputFormat::JSON => output::as_json(json)
            .chain_err(|| ErrorKind::CenterDeviceStatusFailed),
    }
}

fn output_human(json: &str, details: bool) -> Result<()> {
    let status: CenterDeviceStatus = serde_json::from_str(json).chain_err(|| "JSON parsing failed")?;
    match (&status.Status, details) {
        (&Status::Okay, false) =>
            msgln(format!("CenterDevice status is {:?}.", status.Status)),
        (&Status::Okay, true) | (&Status::Warning, _) | (&Status::Failed, _) => {
            msgln(format!("CenterDevice status is {:?}.", status.Status));
            msgln(format!("+ Rest: {:?}", status.Rest.Status));
            msgln(format!("+ Auth: {:?}", status.Auth.Status));
            msgln(format!("+ WebClient: {:?}", status.WebClient.Status));
            msgln(format!("+ PublicLink: {:?}", status.PublicLink.Status));
            msgln(format!("+ DistributorConsole: {:?}", status.DistributorConsole.Status));
            msgln(format!("+ PingDom: {:?}", status.PingDom.Status));
        }
    }
    Ok(())
}

<commit_msg>Curl -> Hyper: CenterDevice status<commit_after>use config::{Config, OutputFormat};
use utils::console::*;
use utils::output;

use clap::{App, Arg, ArgMatches, SubCommand};
use hyper::Client;
use serde_json;
use std::io::Read;
use std::str;
use webbrowser;

pub const NAME: &'static str = "status";

error_chain! {
    errors {
       CenterDeviceStatusFailed {
            description("failed to get CenterDevice status")
            display("failed to get CenterDevice status")
        }
    }
}

#[derive(Deserialize, Debug)]
enum Status {
    Okay,
    Warning,
    Failed,
}

#[allow(non_snake_case)]
#[derive(Deserialize, Debug)]
struct Rest {
    Status: Status,
    Timestamp: String,
    NotificationQueueClientPool: bool,
    FolderHealthCheckSensor: bool,
    DocumentQueueClientPool: bool,
    MetadataStoreResource: bool,
    NotificationStoreResource: bool,
    SearchEngineResource: bool,
    SecurityDataStoreResource: bool,
    SendEmailQueueClientPool: bool,
    UserdataStoreResource: bool,
}

#[allow(non_snake_case)]
#[derive(Deserialize, Debug)]
struct Auth {
    Status: Status,
    Timestamp: String,
    AuthServer: bool,
}

#[allow(non_snake_case)]
#[derive(Deserialize, Debug)]
struct WebClient {
    Status: Status,
    Timestamp: String,
    NotificationAlertingService: bool,
    RestServerSensor: bool,
}

#[allow(non_snake_case)]
#[derive(Deserialize, Debug)]
struct PublicLink {
    Status: Status,
    Timestamp: String,
    PublicLinkClient: bool,
}

#[allow(non_snake_case)]
#[derive(Deserialize, Debug)]
struct DistributorConsole {
    Status: Status,
    Timestamp: String,
    RestServerSensor: bool,
}

#[allow(non_camel_case_types)]
#[derive(Deserialize, Debug)]
enum PingDomStatus {
    up,
    down,
}

#[derive(Deserialize, Debug)]
struct Checks {
    checks: Vec<Vec<Check>>,
}

#[derive(Deserialize, Debug)]
struct Check {
    hostname: String,
    status: PingDomStatus,
    lasttesttime: String,
}

#[allow(non_snake_case)]
#[derive(Deserialize, Debug)]
struct PingDom {
    Status: Status,
    Timestamp: String,
    Checks: Checks,
}

#[allow(non_snake_case)]
#[derive(Deserialize, Debug)]
struct CenterDeviceStatus {
    Status: Status,
    Rest: Rest,
    Auth: Auth,
    WebClient: WebClient,
    PublicLink: PublicLink,
    DistributorConsole: DistributorConsole,
    PingDom: PingDom,
}

pub fn build_sub_cli() -> App<'static, 'static> {
    SubCommand::with_name(NAME)
        .about("Gets public centerdevice status from status server")
        .arg(Arg::with_name("details")
            .long("details")
            .help("Show detailed output"))
        .arg(Arg::with_name("browser")
            .long("browser")
            .help("Open status in web browser"))
}

pub fn call(args: Option<&ArgMatches>, config: &Config) -> Result<()> {
    let details = args.ok_or(false).unwrap().is_present("details");
    let browser = args.ok_or(false).unwrap().is_present("browser");

    if browser {
        info("Opening CenterDevice Status in default browser ...");
        browse(config, details).chain_err(|| ErrorKind::CenterDeviceStatusFailed)
    } else {
        info("Getting CenterDevice Status ...");
        status(config, details).chain_err(|| ErrorKind::CenterDeviceStatusFailed)
    }
}

fn browse(config: &Config, details: bool) -> Result<()> {
    if details {
        webbrowser::open("http://status.centerdevice.de/details.html")
    } else {
        webbrowser::open("http://status.centerdevice.de")
    }.chain_err(|| "Failed to open default browser")?;

    if config.general.output_format == OutputFormat::JSON { msgln("{}"); }

    Ok(())
}

fn status(config: &Config, details: bool) -> Result<()> {
    let json = get_centerdevice_status_json()?;
    output(&json, &config.general.output_format, details)
}

fn get_centerdevice_status_json() -> Result<String> {
    let url = "http://status.centerdevice.de/details.json";
    let mut response = Client::new()
        .get(url)
        .send()
        .chain_err(|| ErrorKind::CenterDeviceStatusFailed)?;

    let mut buffer = Vec::new();
    response.read_to_end(&mut buffer).chain_err(|| "Failed to read HTTP response")?;
    let json = str::from_utf8(&buffer).chain_err(|| "Failed to parse JSON")?;

    Ok(json.to_string())
}

fn output(json: &str, format: &OutputFormat, details: bool) -> Result<()> {
    match *format {
        OutputFormat::HUMAN => output_human(json, details),
        OutputFormat::JSON => output::as_json(json)
            .chain_err(|| ErrorKind::CenterDeviceStatusFailed),
    }
}

fn output_human(json: &str, details: bool) -> Result<()> {
    let status: CenterDeviceStatus = serde_json::from_str(json).chain_err(|| "JSON parsing failed")?;
    match (&status.Status, details) {
        (&Status::Okay, false) =>
            msgln(format!("CenterDevice status is {:?}.", status.Status)),
        (&Status::Okay, true) | (&Status::Warning, _) | (&Status::Failed, _) => {
            msgln(format!("CenterDevice status is {:?}.", status.Status));
            msgln(format!("+ Rest: {:?}", status.Rest.Status));
            msgln(format!("+ Auth: {:?}", status.Auth.Status));
            msgln(format!("+ WebClient: {:?}", status.WebClient.Status));
            msgln(format!("+ PublicLink: {:?}", status.PublicLink.Status));
            msgln(format!("+ DistributorConsole: {:?}", status.DistributorConsole.Status));
            msgln(format!("+ PingDom: {:?}", status.PingDom.Status));
        }
    }
    Ok(())
}

<|endoftext|>


<commit_before>use libc::{size_t, c_double, c_uchar, c_int};

use deflate::calculate_block_size_auto_type;
use lz77::{ZopfliLZ77Store, Lz77Store, lz77_store_from_c};
use symbols::{ZOPFLI_LARGE_FLOAT};
use zopfli::ZopfliOptions;

/// Finds minimum of function f(i) where is is of type size_t, f(i) is of type
/// double, i is in range start-end (excluding end).
/// Outputs the minimum value in *smallest and returns the index of this value.
pub fn find_minimum(f: fn(i: size_t, context: &SplitCostContext) -> c_double, context: &SplitCostContext, start: size_t, end: size_t) -> (size_t, c_double) {
    let mut start = start;
    let mut end = end;
    if end - start < 1024 {
        let mut best = ZOPFLI_LARGE_FLOAT;
        let mut result = start;
        for i in start..end {
            let v = f(i, context);
            if v < best {
                best = v;
                result = i;
            }
        }
        (result, best)
    } else {
        /* Try to find minimum faster by recursively checking multiple points. */
        let num = 9;  /* Good value: 9. ?!?!?!?! */
        let mut p = vec![0; num];
        let mut vp = vec![0.0; num];
        let mut besti;
        let mut best;
        let mut lastbest = ZOPFLI_LARGE_FLOAT;
        let mut pos = start;

        loop {
            if end - start <= num {
                break;
            }

            for i in 0..num {
                p[i] = start + (i + 1) * ((end - start) / (num + 1));
                vp[i] = f(p[i], context);
            }

            besti = 0;
            best = vp[0];

            for i in 1..num {
                if vp[i] < best {
                  best = vp[i];
                  besti = i;
                }
            }
            if best > lastbest {
                break;
            }

            start = if besti == 0 { start } else { p[besti - 1] };
            end = if besti == num - 1 { end } else { p[besti + 1] };

            pos = p[besti];
            lastbest = best;
        }
        (pos, lastbest)
    }
}

/// Returns estimated cost of a block in bits.  It includes the size to encode the
/// tree and the size to encode all literal, length and distance symbols and their
/// extra bits.
///
/// litlens: lz77 lit/lengths
/// dists: ll77 distances
/// lstart: start of block
/// lend: end of block (not inclusive)
pub fn estimate_cost(lz77: &Lz77Store, lstart: size_t, lend: size_t) -> c_double {
    calculate_block_size_auto_type(lz77, lstart, lend)
}

/// Gets the cost which is the sum of the cost of the left and the right section
/// of the data.
/// type: FindMinimumFun
#[allow(non_snake_case)]
pub fn SplitCost(i: size_t, c: &SplitCostContext) -> c_double {
    estimate_cost(c.lz77, c.start, i) + estimate_cost(c.lz77, i, c.end)
}

pub struct SplitCostContext<'a> {
    lz77: &'a Lz77Store,
    start: size_t,
    end: size_t,
}

/// Finds next block to try to split, the largest of the available ones.
/// The largest is chosen to make sure that if only a limited amount of blocks is
/// requested, their sizes are spread evenly.
/// lz77size: the size of the LL77 data, which is the size of the done array here.
/// done: array indicating which blocks starting at that position are no longer
///     splittable (splitting them increases rather than decreases cost).
/// splitpoints: the splitpoints found so far.
/// npoints: the amount of splitpoints found so far.
/// lstart: output variable, giving start of block.
/// lend: output variable, giving end of block.
/// returns 1 if a block was found, 0 if no block found (all are done).
pub fn find_largest_splittable_block(lz77size: size_t, done: *const c_uchar, splitpoints: *const size_t, npoints: size_t, lstart: size_t, lend: size_t) -> (c_int, size_t, size_t) {
    let mut longest = 0;
    let mut found = 0;
    let mut lstart = lstart;
    let mut lend = lend;

    for i in 0..(npoints + 1) {
        let start = if i == 0 { 0 } else { unsafe { *splitpoints.offset(i as isize - 1) } };
        let end = if i == npoints { lz77size - 1 } else { unsafe { *splitpoints.offset(i as isize) } };
        if unsafe { *done.offset(start as isize) } == 0 && end - start > longest {
            lstart = start;
            lend = end;
            found = 1;
            longest = end - start;
        }
    }

    (found, lstart, lend)
}

/// Prints the block split points as decimal and hex values in the terminal.
#[no_mangle]
#[allow(non_snake_case)]
pub extern fn print_block_split_points(lz77: &Lz77Store, lz77splitpoints: *const size_t, nlz77points: size_t) {
    let mut splitpoints = Vec::with_capacity(nlz77points);

    /* The input is given as lz77 indices, but we want to see the uncompressed
    index values. */
    let mut pos = 0;
    if nlz77points > 0 {
        for i in 0..lz77.size() {
            let length = if lz77.dists[i] == 0 {
                1
            } else {
                lz77.litlens[i]
            };
            if unsafe { *lz77splitpoints.offset(splitpoints.len() as isize) } == i {
                splitpoints.push(pos);
                if splitpoints.len() == nlz77points {
                    break;
                }
            }
            pos += length;
        }
    }
    assert!(splitpoints.len() == nlz77points);

    println!("block split points: {} (hex: {})", splitpoints.iter().map(|&sp| format!("{}", sp)).collect::<Vec<_>>().join(" "), splitpoints.iter().map(|&sp| format!("{:x}", sp)).collect::<Vec<_>>().join(" "));
}

#[link(name = "zopfli")]
extern {
    fn AddSorted(value: size_t, out: *mut *mut size_t, outsize: *mut size_t);
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliBlockSplitLZ77(options_ptr: *const ZopfliOptions, lz77_ptr: *const ZopfliLZ77Store, maxblocks: size_t, splitpoints: *mut *mut size_t, npoints: *mut size_t) {
    let options = unsafe {
        assert!(!options_ptr.is_null());
        &*options_ptr
    };
    let lz77_still_pointer = lz77_store_from_c(lz77_ptr);
    let lz77 = unsafe { &*lz77_still_pointer };

    if lz77.size() < 10 {
        return;  /* This code fails on tiny files. */
    }

    let mut llpos;
    let mut numblocks = 1;
    let mut splitcost: c_double;
    let mut origcost;
    let mut done = vec![0; lz77.size()];
    let mut lstart = 0;
    let mut lend = lz77.size();

    loop {
        if maxblocks > 0 && numblocks >= maxblocks {
          break;
        }
        let c = SplitCostContext {
            lz77: lz77,
            start: lstart,
            end: lend,
        };

        assert!(lstart < lend);
        let find_minimum_result = find_minimum(SplitCost, &c, lstart + 1, lend);
        llpos = find_minimum_result.0;
        splitcost = find_minimum_result.1;

        assert!(llpos > lstart);
        assert!(llpos < lend);

        origcost = estimate_cost(lz77, lstart, lend);

        if splitcost > origcost || llpos == lstart + 1 || llpos == lend {
            done[lstart] = 1;
        } else {
            unsafe { AddSorted(llpos, splitpoints, npoints) };
            numblocks += 1;
        }

        let find_block_results = find_largest_splittable_block(lz77.size(), done.as_ptr(), unsafe { *splitpoints }, unsafe { *npoints }, lstart, lend);
        lstart = find_block_results.1;
        lend = find_block_results.2;

        if find_block_results.0 == 0 {
            break;  /* No further split will probably reduce compression. */
        }

        if lend - lstart < 10 {
            break;
        }
    }

    if options.verbose > 0 {
        print_block_split_points(lz77, unsafe { *splitpoints }, unsafe { *npoints });
    }
}
<commit_msg>Make ZopfliBlockSplitLZ77 a wrapper around a rustier fn<commit_after>use libc::{size_t, c_double, c_uchar, c_int};

use deflate::calculate_block_size_auto_type;
use lz77::{ZopfliLZ77Store, Lz77Store, lz77_store_from_c};
use symbols::{ZOPFLI_LARGE_FLOAT};
use zopfli::ZopfliOptions;

/// Finds minimum of function f(i) where is is of type size_t, f(i) is of type
/// double, i is in range start-end (excluding end).
/// Outputs the minimum value in *smallest and returns the index of this value.
pub fn find_minimum(f: fn(i: size_t, context: &SplitCostContext) -> c_double, context: &SplitCostContext, start: size_t, end: size_t) -> (size_t, c_double) {
    let mut start = start;
    let mut end = end;
    if end - start < 1024 {
        let mut best = ZOPFLI_LARGE_FLOAT;
        let mut result = start;
        for i in start..end {
            let v = f(i, context);
            if v < best {
                best = v;
                result = i;
            }
        }
        (result, best)
    } else {
        /* Try to find minimum faster by recursively checking multiple points. */
        let num = 9;  /* Good value: 9. ?!?!?!?! */
        let mut p = vec![0; num];
        let mut vp = vec![0.0; num];
        let mut besti;
        let mut best;
        let mut lastbest = ZOPFLI_LARGE_FLOAT;
        let mut pos = start;

        loop {
            if end - start <= num {
                break;
            }

            for i in 0..num {
                p[i] = start + (i + 1) * ((end - start) / (num + 1));
                vp[i] = f(p[i], context);
            }

            besti = 0;
            best = vp[0];

            for i in 1..num {
                if vp[i] < best {
                  best = vp[i];
                  besti = i;
                }
            }
            if best > lastbest {
                break;
            }

            start = if besti == 0 { start } else { p[besti - 1] };
            end = if besti == num - 1 { end } else { p[besti + 1] };

            pos = p[besti];
            lastbest = best;
        }
        (pos, lastbest)
    }
}

/// Returns estimated cost of a block in bits.  It includes the size to encode the
/// tree and the size to encode all literal, length and distance symbols and their
/// extra bits.
///
/// litlens: lz77 lit/lengths
/// dists: ll77 distances
/// lstart: start of block
/// lend: end of block (not inclusive)
pub fn estimate_cost(lz77: &Lz77Store, lstart: size_t, lend: size_t) -> c_double {
    calculate_block_size_auto_type(lz77, lstart, lend)
}

/// Gets the cost which is the sum of the cost of the left and the right section
/// of the data.
/// type: FindMinimumFun
#[allow(non_snake_case)]
pub fn SplitCost(i: size_t, c: &SplitCostContext) -> c_double {
    estimate_cost(c.lz77, c.start, i) + estimate_cost(c.lz77, i, c.end)
}

pub struct SplitCostContext<'a> {
    lz77: &'a Lz77Store,
    start: size_t,
    end: size_t,
}

/// Finds next block to try to split, the largest of the available ones.
/// The largest is chosen to make sure that if only a limited amount of blocks is
/// requested, their sizes are spread evenly.
/// lz77size: the size of the LL77 data, which is the size of the done array here.
/// done: array indicating which blocks starting at that position are no longer
///     splittable (splitting them increases rather than decreases cost).
/// splitpoints: the splitpoints found so far.
/// npoints: the amount of splitpoints found so far.
/// lstart: output variable, giving start of block.
/// lend: output variable, giving end of block.
/// returns 1 if a block was found, 0 if no block found (all are done).
pub fn find_largest_splittable_block(lz77size: size_t, done: *const c_uchar, splitpoints: &Vec<size_t>, lstart: size_t, lend: size_t) -> (c_int, size_t, size_t) {
    let mut longest = 0;
    let mut found = 0;
    let mut lstart = lstart;
    let mut lend = lend;

    let npoints = splitpoints.len();

    for i in 0..(npoints + 1) {
        let start = if i == 0 { 0 } else { splitpoints[i - 1] };
        let end = if i == npoints { lz77size - 1 } else { splitpoints[i] };
        if unsafe { *done.offset(start as isize) } == 0 && end - start > longest {
            lstart = start;
            lend = end;
            found = 1;
            longest = end - start;
        }
    }

    (found, lstart, lend)
}

/// Prints the block split points as decimal and hex values in the terminal.
#[no_mangle]
#[allow(non_snake_case)]
pub extern fn print_block_split_points(lz77: &Lz77Store, lz77splitpoints: &Vec<size_t>) {
    let nlz77points = lz77splitpoints.len();
    let mut splitpoints = Vec::with_capacity(nlz77points);

    /* The input is given as lz77 indices, but we want to see the uncompressed
    index values. */
    let mut pos = 0;
    if nlz77points > 0 {
        for i in 0..lz77.size() {
            let length = if lz77.dists[i] == 0 {
                1
            } else {
                lz77.litlens[i]
            };
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == nlz77points {
                    break;
                }
            }
            pos += length;
        }
    }
    assert!(splitpoints.len() == nlz77points);

    println!("block split points: {} (hex: {})", splitpoints.iter().map(|&sp| format!("{}", sp)).collect::<Vec<_>>().join(" "), splitpoints.iter().map(|&sp| format!("{:x}", sp)).collect::<Vec<_>>().join(" "));
}

#[link(name = "zopfli")]
extern {
    fn AddSorted(value: size_t, out: *mut *mut size_t, outsize: *mut size_t);
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliBlockSplitLZ77(options_ptr: *const ZopfliOptions, lz77_ptr: *const ZopfliLZ77Store, maxblocks: size_t, splitpoints: *mut *mut size_t, npoints: *mut size_t) {
    let options = unsafe {
        assert!(!options_ptr.is_null());
        &*options_ptr
    };
    let lz77_still_pointer = lz77_store_from_c(lz77_ptr);
    let lz77 = unsafe { &*lz77_still_pointer };

    let mut splitpoints_vec = Vec::with_capacity(maxblocks);

    blocksplit_lz77(options, lz77, maxblocks, &mut splitpoints_vec);

    for point in splitpoints_vec {
        unsafe {
            AddSorted(point, splitpoints, npoints);
        }
    }
}

pub fn blocksplit_lz77(options: &ZopfliOptions, lz77: &Lz77Store, maxblocks: size_t, splitpoints: &mut Vec<size_t>) {

    if lz77.size() < 10 {
        return;  /* This code fails on tiny files. */
    }

    let mut llpos;
    let mut numblocks = 1;
    let mut splitcost: c_double;
    let mut origcost;
    let mut done = vec![0; lz77.size()];
    let mut lstart = 0;
    let mut lend = lz77.size();

    loop {
        if maxblocks > 0 && numblocks >= maxblocks {
          break;
        }
        let c = SplitCostContext {
            lz77: lz77,
            start: lstart,
            end: lend,
        };

        assert!(lstart < lend);
        let find_minimum_result = find_minimum(SplitCost, &c, lstart + 1, lend);
        llpos = find_minimum_result.0;
        splitcost = find_minimum_result.1;

        assert!(llpos > lstart);
        assert!(llpos < lend);

        origcost = estimate_cost(lz77, lstart, lend);

        if splitcost > origcost || llpos == lstart + 1 || llpos == lend {
            done[lstart] = 1;
        } else {
            splitpoints.push(llpos);
            splitpoints.sort();
            numblocks += 1;
        }

        let find_block_results = find_largest_splittable_block(lz77.size(), done.as_ptr(), splitpoints, lstart, lend);
        lstart = find_block_results.1;
        lend = find_block_results.2;

        if find_block_results.0 == 0 {
            break;  /* No further split will probably reduce compression. */
        }

        if lend - lstart < 10 {
            break;
        }
    }

    if options.verbose > 0 {
        print_block_split_points(lz77, splitpoints);
    }
}
<|endoftext|>


<commit_before>use dvec::{ DVec };
use cmp::{ Ord, Eq };
use to_bytes::{ IterBytes };
use hash::{ Hash };
use std::map::{ HashMap };

pub fn each_fib(f: fn(uint)->bool) {
    let mut (prev, cur) = (0, 1);
    loop {
        if !f(cur) { break; }
        let next = prev + cur;
        prev = cur;
        cur  = next;
    }
}

pub fn factorial(n: uint) -> uint {
    let mut prod = 1;
    for uint::range(1, n + 1) |n| { prod *= n; }
    return prod;
}

fn histogram<T: Eq IterBytes Hash Const Copy>(v: &[T]) -> HashMap<T, uint> {
    let map = HashMap::<T, uint>();
    for v.each |k| {
        let val = do map.find(*k).map_default(1) |v| { v + 1 };
        map.insert(*k, val);
    }
    return map;
}

pub fn num_of_permutations<T: Eq IterBytes Hash Copy>(hist: HashMap<T, uint>) -> uint {
    let mut sum = 0;
    let mut div = 1;
    for hist.each_value |cnt| { sum += cnt; div *= factorial(cnt); }
    return factorial(sum) / div;
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_each_fib() {
        let fib = ~[ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233 ];
        let mut calc = ~[];
        for each_fib |f| {
            if f > fib.last() { break; }
            calc += [ f ];
        }
        assert fib == calc;
    }

    #[test]
    fn test_factorial() {
        assert factorial(0) == 1;
        assert factorial(1) == 1;
        assert factorial(2) == 2;
        assert factorial(3) == 6;
        assert factorial(10) == 3628800;
    }

    #[test]
    fn test_histogram() {
        fn check(inp: &[uint], result: &[(uint, uint)]) {
            let mut vec = ~[];
            for histogram(inp).each |k, v| { vec += [(k, v)]; }
            let sorted = std::sort::merge_sort(|a, b| a.first() <= b.first(), vec);
            assert result == sorted;
        }
        check(&[1, 2, 3], &[(1, 1), (2, 1), (3, 1)]);
        check(&[1, 1, 1, 2, 2, 3, 3, 4], &[(1, 3), (2, 2), (3, 2), (4, 1)]);
        check(&[1, 1, 1, 2, 2, 1, 1], &[(1, 5), (2, 2)]);
        check(&[], &[]);
    }

    #[test]
    fn test_num_of_permutasions() {
        assert num_of_permutations(histogram::<uint>(&[])) == 1;
        assert num_of_permutations(histogram(&[1, 2, 3])) == 6;
        assert num_of_permutations(histogram(&[1, 1, 1, 2, 3])) == 20;
        assert num_of_permutations(histogram(&[1, 1, 1, 2, 3, 1, 1])) == 42;
    }
}
<commit_msg>Add pub to euler::calc::histogram<commit_after>use dvec::{ DVec };
use cmp::{ Ord, Eq };
use to_bytes::{ IterBytes };
use hash::{ Hash };
use std::map::{ HashMap };

pub fn each_fib(f: fn(uint)->bool) {
    let mut (prev, cur) = (0, 1);
    loop {
        if !f(cur) { break; }
        let next = prev + cur;
        prev = cur;
        cur  = next;
    }
}

pub fn factorial(n: uint) -> uint {
    let mut prod = 1;
    for uint::range(1, n + 1) |n| { prod *= n; }
    return prod;
}

pub fn histogram<T: Eq IterBytes Hash Const Copy>(v: &[T]) -> HashMap<T, uint> {
    let map = HashMap::<T, uint>();
    for v.each |k| {
        let val = do map.find(*k).map_default(1) |v| { v + 1 };
        map.insert(*k, val);
    }
    return map;
}

pub fn num_of_permutations<T: Eq IterBytes Hash Copy>(hist: HashMap<T, uint>) -> uint {
    let mut sum = 0;
    let mut div = 1;
    for hist.each_value |cnt| { sum += cnt; div *= factorial(cnt); }
    return factorial(sum) / div;
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_each_fib() {
        let fib = ~[ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233 ];
        let mut calc = ~[];
        for each_fib |f| {
            if f > fib.last() { break; }
            calc += [ f ];
        }
        assert fib == calc;
    }

    #[test]
    fn test_factorial() {
        assert factorial(0) == 1;
        assert factorial(1) == 1;
        assert factorial(2) == 2;
        assert factorial(3) == 6;
        assert factorial(10) == 3628800;
    }

    #[test]
    fn test_histogram() {
        fn check(inp: &[uint], result: &[(uint, uint)]) {
            let mut vec = ~[];
            for histogram(inp).each |k, v| { vec += [(k, v)]; }
            let sorted = std::sort::merge_sort(|a, b| a.first() <= b.first(), vec);
            assert result == sorted;
        }
        check(&[1, 2, 3], &[(1, 1), (2, 1), (3, 1)]);
        check(&[1, 1, 1, 2, 2, 3, 3, 4], &[(1, 3), (2, 2), (3, 2), (4, 1)]);
        check(&[1, 1, 1, 2, 2, 1, 1], &[(1, 5), (2, 2)]);
        check(&[], &[]);
    }

    #[test]
    fn test_num_of_permutasions() {
        assert num_of_permutations(histogram::<uint>(&[])) == 1;
        assert num_of_permutations(histogram(&[1, 2, 3])) == 6;
        assert num_of_permutations(histogram(&[1, 1, 1, 2, 3])) == 20;
        assert num_of_permutations(histogram(&[1, 1, 1, 2, 3, 1, 1])) == 42;
    }
}
<|endoftext|>


<commit_before>macro_rules! check_arity {
    ($name:expr, $len:expr, $exact:expr) => ({
        let len = $len as u32;
        if len != $exact {
            raise_condition!(format!("arity mismatch for {}: expected: {}, got: {}", $name, $exact, len));
        }
    });

    ($name:expr, $len:expr, $lo:expr, $hi:expr) => ({
        let len = $len as u32;
        if len < $lo || len > $hi {
            raise_condition!(format!("arity mismatch for {}: expected: {}..{}, got: {}", $name, $lo, $hi, len));
        }
    });

    ($name:expr, $len:expr, min => $min:expr) => ({
        let len = $len as u32;
        if len < $min {
            raise_condition!(format!("arity mismatch for {}: expected: {}.., got: {}", $name, $min, len));
        }
    });
}

macro_rules! try_unwrap_type {
    ($fn_name:expr, $type_name:expr, $unwrap_fn:path, $t:expr, $interpreter:expr) => ({
        match $unwrap_fn($t) {
            Some(x) => x,
            None => {
                let s = format!("{} expected {}, got: {}", $fn_name, $type_name, $t.to_string(&$interpreter.interner));
                return Value::new_condition(Value::new_string(s));
            }
        }
    });
}

macro_rules! new_condition {
    ($msg:expr) => (
        Value::new_condition(Value::new_string($msg))
    )
}

macro_rules! raise_condition {
    ($msg:expr) => (
        return new_condition!($msg);
    )
}

macro_rules! assert_or_condition {
    ($b:expr, $msg:expr) => ({
        if !$b {
            raise_condition!($msg)
        }
    })
}

macro_rules! eval_args {
    (fn $func:ident($args:ident : $arg_ty:ty) -> $ret_ty:ty $blk:block) =>
    (
        pub fn $func(interpreter: &mut Interpreter, args: $arg_ty) -> $ret_ty {
            fn inner($args: $arg_ty) -> $ret_ty $blk;
            for x in args.iter_mut() {
                *x = interpreter.evaluate(x);
            }
            inner(args)
        }
    );

    (fn $func:ident($interpreter:ident : &mut Interpreter, $args:ident : $arg_ty:ty) -> $ret_ty:ty $blk:block) =>
    (
        pub fn $func(interpreter: &mut Interpreter, args: $arg_ty) -> $ret_ty {
            fn inner($interpreter: &mut Interpreter, $args: $arg_ty) -> $ret_ty $blk;
            for x in args.iter_mut() {
                *x = interpreter.evaluate(x);
            }
            inner(interpreter, args)
        }
    );
}
<commit_msg>document macros in native<commit_after>// this is used to automate arity checking of native functions
// name is always the functions name as string, eg. for define name is "define"
// len is always the number of arguments
macro_rules! check_arity {
    // exact arity
    ($name:expr, $len:expr, $exact:expr) => ({
        let len = $len as u32;
        if len != $exact {
            raise_condition!(format!("arity mismatch for {}: expected: {}, got: {}", $name, $exact, len));
        }
    });

    // range
    ($name:expr, $len:expr, $lo:expr, $hi:expr) => ({
        let len = $len as u32;
        if len < $lo || len > $hi {
            raise_condition!(format!("arity mismatch for {}: expected: {}..{}, got: {}", $name, $lo, $hi, len));
        }
    });

    // minimum
    ($name:expr, $len:expr, min => $min:expr) => ({
        let len = $len as u32;
        if len < $min {
            raise_condition!(format!("arity mismatch for {}: expected: {}.., got: {}", $name, $min, len));
        }
    });
}

// this automates type checking. If the expected type is not found, a condition is returned early
// name: functions name
// type_name: name of type, eg. "string" or "list"
// unwrap_fn: a fn taking a value and returning Option<T>, where T is the rust type that is expected from the value.
// value: the value to unwrap
// interpreter: &mut Interpreter
macro_rules! try_unwrap_type {
    ($fn_name:expr, $type_name:expr, $unwrap_fn:path, $value:expr, $interpreter:expr) => ({
        match $unwrap_fn($value) {
            Some(x) => x,
            None => {
                let s = format!("{} expected {}, got: {}", $fn_name, $type_name, $value.to_string(&$interpreter.interner));
                return Value::new_condition(Value::new_string(s));
            }
        }
    });
}

macro_rules! new_condition {
    ($msg:expr) => (
        Value::new_condition(Value::new_string($msg))
    )
}

macro_rules! raise_condition {
    ($msg:expr) => (
        return new_condition!($msg);
    )
}

macro_rules! assert_or_condition {
    ($b:expr, $msg:expr) => ({
        if !$b {
            raise_condition!($msg)
        }
    })
}

// This automates the evaluation of arguments supplied to functions
// arguments are just evaluated in order
macro_rules! eval_args {
    // args is an array of already evaluated args
    (fn $func:ident($args:ident : $arg_ty:ty) -> $ret_ty:ty $blk:block) =>
    (
        pub fn $func(interpreter: &mut Interpreter, args: $arg_ty) -> $ret_ty {
            fn inner($args: $arg_ty) -> $ret_ty $blk;
            for x in args.iter_mut() {
                *x = interpreter.evaluate(x);
            }
            inner(args)
        }
    );

    // same as above, but with interpreter available
    (fn $func:ident($interpreter:ident : &mut Interpreter, $args:ident : $arg_ty:ty) -> $ret_ty:ty $blk:block) =>
    (
        pub fn $func(interpreter: &mut Interpreter, args: $arg_ty) -> $ret_ty {
            fn inner($interpreter: &mut Interpreter, $args: $arg_ty) -> $ret_ty $blk;
            for x in args.iter_mut() {
                *x = interpreter.evaluate(x);
            }
            inner(interpreter, args)
        }
    );
}
<|endoftext|>


<commit_before>//! "Nlist" style symbols in this binary - beware, like most symbol tables in most binary formats, they are strippable, and should not be relied upon, see the imports and exports modules for something more permanent.
//!
//! Symbols are essentially a type, offset, and the symbol name

use scroll::{ctx, Pread};
use scroll::ctx::SizeWith;
use error;
use container::{self, Container};
use mach::load_command;
use core::fmt::{self, Debug};

// If the type is N_SECT then the n_sect field contains an ordinal of the
// section the symbol is defined in.  The sections are numbered from 1 and
// refer to sections in order they appear in the load commands for the file
// they are in.  This means the same ordinal may very well refer to different
// sections in different files.

// The n_value field for all symbol table entries (including N_STAB's) gets
// updated by the link editor based on the value of it's n_sect field and where
// the section n_sect references gets relocated.  If the value of the n_sect
// field is NO_SECT then it's n_value field is not changed by the link editor.
/// symbol is not in any section
pub const NO_SECT: u8 = 0;
/// 1 thru 255 inclusive
pub const MAX_SECT: u8 = 255;

/// undefined, n_sect == NO_SECT
pub const N_UNDF: u8 = 0x0;
/// absolute, n_sect == NO_SECT
pub const N_ABS:  u8 = 0x2;
/// defined in section number n_sect
pub const N_SECT: u8 = 0xe;
/// prebound undefined (defined in a dylib)
pub const N_PBUD: u8 = 0xc;
/// indirect
pub const N_INDR: u8 = 0xa;

pub const NLIST_TYPE_MASK: u8 = 0xe;
pub const NLIST_TYPE_GLOBAL: u8 = 0x1;
pub const NLIST_TYPE_LOCAL: u8 = 0x0;

pub fn n_type_to_str(n_type: u8) -> &'static str {
    match n_type {
        N_UNDF => "N_UNDF",
        N_ABS => "N_ABS",
        N_SECT => "N_SECT",
        N_PBUD => "N_PBUD",
        N_INDR => "N_INDR",
        _ => "UNKNOWN_N_TYPE"
    }
}

#[repr(C)]
#[derive(Clone, Copy, Pread, Pwrite, SizeWith)]
pub struct Nlist32 {
    /// index into the string table
    pub n_strx: u32,
    /// type flag, see below
    pub n_type: u8,
    /// section number or NO_SECT
    pub n_sect: u8,
    /// see <mach-o/stab.h>
    pub n_desc: u16,
    /// value of this symbol (or stab offset)
    pub n_value: u32,
}

pub const SIZEOF_NLIST_32: usize = 12;

impl Debug for Nlist32 {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "strx: {:04} type: {:#02x} sect: {:#x} desc: {:#03x} value: {:#x}",
               self.n_strx,
               self.n_type,
               self.n_sect,
               self.n_desc,
               self.n_value,
        )
    }
}

#[repr(C)]
#[derive(Clone, Copy, Pread, Pwrite, SizeWith)]
pub struct Nlist64 {
    /// index into the string table
    pub n_strx: u32,
    /// type flag, see below
    pub n_type: u8,
    /// section number or NO_SECT
    pub n_sect: u8,
    /// see <mach-o/stab.h>
    pub n_desc: u16,
    /// value of this symbol (or stab offset)
    pub n_value: u64,
}

pub const SIZEOF_NLIST_64: usize = 16;

impl Debug for Nlist64 {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "strx: {:04} type: {:#02x} sect: {:#x} desc: {:#03x} value: {:#x}",
               self.n_strx,
               self.n_type,
               self.n_sect,
               self.n_desc,
               self.n_value,
        )
    }
}

#[derive(Debug, Clone)]
pub struct Nlist {
    /// index into the string table
    pub n_strx: usize,
    /// type flag, see below
    pub n_type: u8,
    /// section number or NO_SECT
    pub n_sect: usize,
    /// see <mach-o/stab.h>
    pub n_desc: u16,
    /// value of this symbol (or stab offset)
    pub n_value: u64,
}

impl Nlist {
    /// Gets this symbol's type in bits 0xe
    pub fn get_type(&self) -> u8 {
        self.n_type & NLIST_TYPE_MASK
    }
    /// Gets the str representation of the type of this symbol
    pub fn type_str(&self) -> &'static str {
        n_type_to_str(self.get_type())
    }
    /// Whether this symbol is global or not
    pub fn is_global(&self) -> bool {
        self.n_type & !NLIST_TYPE_MASK == NLIST_TYPE_GLOBAL
    }
    /// Whether this symbol is undefined or not
    pub fn is_undefined(&self) -> bool {
        self.n_sect == 0 && self.n_type & NLIST_TYPE_MASK == 0
    }
}

impl ctx::SizeWith<container::Ctx> for Nlist {
    type Units = usize;
    fn size_with(ctx: &container::Ctx) -> usize {
        use container::Container;
        match ctx.container {
            Container::Little => {
                SIZEOF_NLIST_32
            },
            Container::Big => {
                SIZEOF_NLIST_64
            },
        }
    }
}

impl From<Nlist32> for Nlist {
    fn from(nlist: Nlist32) -> Self {
        Nlist {
            n_strx: nlist.n_strx as usize,
            n_type: nlist.n_type,
            n_sect: nlist.n_sect as usize,
            n_desc: nlist.n_desc,
            n_value: nlist.n_value as u64,
        }
    }
}

impl From<Nlist64> for Nlist {
    fn from(nlist: Nlist64) -> Self {
        Nlist {
            n_strx: nlist.n_strx as usize,
            n_type: nlist.n_type,
            n_sect: nlist.n_sect as usize,
            n_desc: nlist.n_desc,
            n_value: nlist.n_value,
        }
    }
}

impl<'a> ctx::TryFromCtx<'a, container::Ctx> for Nlist {
    type Error = ::error::Error;
    type Size = usize;
    fn try_from_ctx(bytes: &'a [u8], container::Ctx { container, le }: container::Ctx) -> ::error::Result<(Self, Self::Size)> {
        let nlist = match container {
            Container::Little => {
                (bytes.pread_with::<Nlist32>(0, le)?.into(), SIZEOF_NLIST_32)
            },
            Container::Big => {
                (bytes.pread_with::<Nlist64>(0, le)?.into(), SIZEOF_NLIST_64)
            },
        };
        Ok(nlist)
    }
}

#[derive(Debug, Clone, Copy, Default)]
pub struct SymbolsCtx {
    pub nsyms: usize,
    pub strtab: usize,
    pub ctx: container::Ctx,
}

impl<'a, T: ?Sized> ctx::TryFromCtx<'a, SymbolsCtx, T> for Symbols<'a> where T: AsRef<[u8]> {
    type Error = ::error::Error;
    type Size = usize;
    fn try_from_ctx(bytes: &'a T, SymbolsCtx {
        nsyms, strtab, ctx
    }: SymbolsCtx) -> ::error::Result<(Self, Self::Size)> {
        let data = bytes.as_ref();
        Ok ((Symbols {
            data: data,
            start: 0,
            nsyms: nsyms,
            strtab: strtab,
            ctx: ctx,
        }, data.len()))
    }
}

#[derive(Default)]
pub struct SymbolIterator<'a> {
    data: &'a [u8],
    nsyms: usize,
    offset: usize,
    count: usize,
    ctx: container::Ctx,
    strtab: usize,
}

impl<'a> Iterator for SymbolIterator<'a> {
    type Item = error::Result<(&'a str, Nlist)>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.count >= self.nsyms {
            None
        } else {
            self.count += 1;
            match self.data.gread_with::<Nlist>(&mut self.offset, self.ctx) {
                Ok(symbol) => {
                    match self.data.pread(self.strtab + symbol.n_strx) {
                        Ok(name) => {
                            Some(Ok((name, symbol)))
                        },
                        Err(e) => return Some(Err(e.into()))
                    }
                },
                Err(e) => return Some(Err(e.into()))
            }
        }
    }
}

/// A zero-copy "nlist" style symbol table ("stab"), including the string table
pub struct Symbols<'a> {
    data: &'a [u8],
    start: usize,
    nsyms: usize,
    // TODO: we can use an actual strtab here and tie it to symbols lifetime
    strtab: usize,
    ctx: container::Ctx,
}

impl<'a, 'b> IntoIterator for &'b Symbols<'a> {
    type Item = <SymbolIterator<'a> as Iterator>::Item;
    type IntoIter = SymbolIterator<'a>;
    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a> Symbols<'a> {
    /// Creates a new symbol table with `count` elements, from the `start` offset, using the string table at `strtab`, with a _default_ ctx.
    ////
    /// **Beware**, this will provide incorrect results if you construct this on a 32-bit mach binary, using a 64-bit machine; use `parse` instead if you want 32/64 bit support
    pub fn new(bytes: &'a [u8], start: usize, count: usize, strtab: usize) -> error::Result<Symbols<'a>> {
        let nsyms = count;
        Ok (Symbols {
            data: bytes,
            start: start,
            nsyms: nsyms,
            strtab: strtab,
            ctx: container::Ctx::default(),
        })
    }
    pub fn parse(bytes: &'a [u8], symtab: &load_command::SymtabCommand, ctx: container::Ctx) -> error::Result<Symbols<'a>> {
        // we need to normalize the strtab offset before we receive the truncated bytes in pread_with
        let strtab = symtab.stroff - symtab.symoff;
        Ok(bytes.pread_with(symtab.symoff as usize, SymbolsCtx { nsyms: symtab.nsyms as usize, strtab: strtab as usize, ctx: ctx })?)
    }

    pub fn iter(&self) -> SymbolIterator<'a> {
        SymbolIterator {
            offset: self.start as usize,
            nsyms: self.nsyms as usize,
            count: 0,
            data: self.data,
            ctx: self.ctx,
            strtab: self.strtab,
        }
    }

    /// Parses a single Nlist symbol from the binary, with its accompanying name
    pub fn get(&self, index: usize) -> ::error::Result<(&'a str, Nlist)> {
        let sym: Nlist = self.data.pread_with(self.start + (index * Nlist::size_with(&self.ctx)), self.ctx)?;
        let name = self.data.pread(self.strtab + sym.n_strx)?;
        Ok((name, sym))
    }
}

impl<'a> Debug for Symbols<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        writeln!(fmt, "Data: {} start: {:#?}, nsyms: {} strtab: {:#x}", self.data.len(), self.start, self.nsyms, self.strtab)?;
        writeln!(fmt, "Symbols: {{")?;
        for (i, res) in self.iter().enumerate() {
            match res {
                Ok((name, nlist)) => {
                    writeln!(fmt, "{: >10x} {} sect: {:#x} type: {:#02x} desc: {:#03x}", nlist.n_value, name, nlist.n_sect, nlist.n_type, nlist.n_desc)?;
                },
                Err(error) => {
                    writeln!(fmt, "  Bad symbol, index: {}, sym: {:?}", i, error)?;
                }
            }
        }
        writeln!(fmt, "}}")
    }
}
<commit_msg>mach: add more n_type mask constants<commit_after>//! "Nlist" style symbols in this binary - beware, like most symbol tables in most binary formats, they are strippable, and should not be relied upon, see the imports and exports modules for something more permanent.
//!
//! Symbols are essentially a type, offset, and the symbol name

use scroll::{ctx, Pread};
use scroll::ctx::SizeWith;
use error;
use container::{self, Container};
use mach::load_command;
use core::fmt::{self, Debug};

// The n_type field really contains four fields which are used via the following masks.
/// if any of these bits set, a symbolic debugging entry
pub const N_STAB: u8 = 0xe0;
/// private external symbol bit
pub const N_PEXT: u8 = 0x10;
/// mask for the type bits
pub const N_TYPE: u8 = 0x0e;
/// external symbol bit, set for external symbols
pub const N_EXT: u8 = 0x01;

// If the type is N_SECT then the n_sect field contains an ordinal of the
// section the symbol is defined in.  The sections are numbered from 1 and
// refer to sections in order they appear in the load commands for the file
// they are in.  This means the same ordinal may very well refer to different
// sections in different files.

// The n_value field for all symbol table entries (including N_STAB's) gets
// updated by the link editor based on the value of it's n_sect field and where
// the section n_sect references gets relocated.  If the value of the n_sect
// field is NO_SECT then it's n_value field is not changed by the link editor.
/// symbol is not in any section
pub const NO_SECT: u8 = 0;
/// 1 thru 255 inclusive
pub const MAX_SECT: u8 = 255;

/// undefined, n_sect == NO_SECT
pub const N_UNDF: u8 = 0x0;
/// absolute, n_sect == NO_SECT
pub const N_ABS:  u8 = 0x2;
/// defined in section number n_sect
pub const N_SECT: u8 = 0xe;
/// prebound undefined (defined in a dylib)
pub const N_PBUD: u8 = 0xc;
/// indirect
pub const N_INDR: u8 = 0xa;

pub const NLIST_TYPE_MASK: u8 = 0xe;
pub const NLIST_TYPE_GLOBAL: u8 = 0x1;
pub const NLIST_TYPE_LOCAL: u8 = 0x0;

pub fn n_type_to_str(n_type: u8) -> &'static str {
    match n_type {
        N_UNDF => "N_UNDF",
        N_ABS => "N_ABS",
        N_SECT => "N_SECT",
        N_PBUD => "N_PBUD",
        N_INDR => "N_INDR",
        _ => "UNKNOWN_N_TYPE"
    }
}

#[repr(C)]
#[derive(Clone, Copy, Pread, Pwrite, SizeWith)]
pub struct Nlist32 {
    /// index into the string table
    pub n_strx: u32,
    /// type flag, see below
    pub n_type: u8,
    /// section number or NO_SECT
    pub n_sect: u8,
    /// see <mach-o/stab.h>
    pub n_desc: u16,
    /// value of this symbol (or stab offset)
    pub n_value: u32,
}

pub const SIZEOF_NLIST_32: usize = 12;

impl Debug for Nlist32 {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "strx: {:04} type: {:#02x} sect: {:#x} desc: {:#03x} value: {:#x}",
               self.n_strx,
               self.n_type,
               self.n_sect,
               self.n_desc,
               self.n_value,
        )
    }
}

#[repr(C)]
#[derive(Clone, Copy, Pread, Pwrite, SizeWith)]
pub struct Nlist64 {
    /// index into the string table
    pub n_strx: u32,
    /// type flag, see below
    pub n_type: u8,
    /// section number or NO_SECT
    pub n_sect: u8,
    /// see <mach-o/stab.h>
    pub n_desc: u16,
    /// value of this symbol (or stab offset)
    pub n_value: u64,
}

pub const SIZEOF_NLIST_64: usize = 16;

impl Debug for Nlist64 {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "strx: {:04} type: {:#02x} sect: {:#x} desc: {:#03x} value: {:#x}",
               self.n_strx,
               self.n_type,
               self.n_sect,
               self.n_desc,
               self.n_value,
        )
    }
}

#[derive(Debug, Clone)]
pub struct Nlist {
    /// index into the string table
    pub n_strx: usize,
    /// type flag, see below
    pub n_type: u8,
    /// section number or NO_SECT
    pub n_sect: usize,
    /// see <mach-o/stab.h>
    pub n_desc: u16,
    /// value of this symbol (or stab offset)
    pub n_value: u64,
}

impl Nlist {
    /// Gets this symbol's type in bits 0xe
    pub fn get_type(&self) -> u8 {
        self.n_type & N_TYPE
    }
    /// Gets the str representation of the type of this symbol
    pub fn type_str(&self) -> &'static str {
        n_type_to_str(self.get_type())
    }
    /// Whether this symbol is global or not
    pub fn is_global(&self) -> bool {
        self.n_type & N_EXT != 0
    }
    /// Whether this symbol is undefined or not
    pub fn is_undefined(&self) -> bool {
        self.n_sect == 0 && self.n_type & N_TYPE == N_UNDF
    }
    /// Whether this symbol is a symbolic debugging entry
    pub fn is_stab(&self) -> bool {
        self.n_type & N_STAB != 0
    }
}

impl ctx::SizeWith<container::Ctx> for Nlist {
    type Units = usize;
    fn size_with(ctx: &container::Ctx) -> usize {
        use container::Container;
        match ctx.container {
            Container::Little => {
                SIZEOF_NLIST_32
            },
            Container::Big => {
                SIZEOF_NLIST_64
            },
        }
    }
}

impl From<Nlist32> for Nlist {
    fn from(nlist: Nlist32) -> Self {
        Nlist {
            n_strx: nlist.n_strx as usize,
            n_type: nlist.n_type,
            n_sect: nlist.n_sect as usize,
            n_desc: nlist.n_desc,
            n_value: nlist.n_value as u64,
        }
    }
}

impl From<Nlist64> for Nlist {
    fn from(nlist: Nlist64) -> Self {
        Nlist {
            n_strx: nlist.n_strx as usize,
            n_type: nlist.n_type,
            n_sect: nlist.n_sect as usize,
            n_desc: nlist.n_desc,
            n_value: nlist.n_value,
        }
    }
}

impl<'a> ctx::TryFromCtx<'a, container::Ctx> for Nlist {
    type Error = ::error::Error;
    type Size = usize;
    fn try_from_ctx(bytes: &'a [u8], container::Ctx { container, le }: container::Ctx) -> ::error::Result<(Self, Self::Size)> {
        let nlist = match container {
            Container::Little => {
                (bytes.pread_with::<Nlist32>(0, le)?.into(), SIZEOF_NLIST_32)
            },
            Container::Big => {
                (bytes.pread_with::<Nlist64>(0, le)?.into(), SIZEOF_NLIST_64)
            },
        };
        Ok(nlist)
    }
}

#[derive(Debug, Clone, Copy, Default)]
pub struct SymbolsCtx {
    pub nsyms: usize,
    pub strtab: usize,
    pub ctx: container::Ctx,
}

impl<'a, T: ?Sized> ctx::TryFromCtx<'a, SymbolsCtx, T> for Symbols<'a> where T: AsRef<[u8]> {
    type Error = ::error::Error;
    type Size = usize;
    fn try_from_ctx(bytes: &'a T, SymbolsCtx {
        nsyms, strtab, ctx
    }: SymbolsCtx) -> ::error::Result<(Self, Self::Size)> {
        let data = bytes.as_ref();
        Ok ((Symbols {
            data: data,
            start: 0,
            nsyms: nsyms,
            strtab: strtab,
            ctx: ctx,
        }, data.len()))
    }
}

#[derive(Default)]
pub struct SymbolIterator<'a> {
    data: &'a [u8],
    nsyms: usize,
    offset: usize,
    count: usize,
    ctx: container::Ctx,
    strtab: usize,
}

impl<'a> Iterator for SymbolIterator<'a> {
    type Item = error::Result<(&'a str, Nlist)>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.count >= self.nsyms {
            None
        } else {
            self.count += 1;
            match self.data.gread_with::<Nlist>(&mut self.offset, self.ctx) {
                Ok(symbol) => {
                    match self.data.pread(self.strtab + symbol.n_strx) {
                        Ok(name) => {
                            Some(Ok((name, symbol)))
                        },
                        Err(e) => return Some(Err(e.into()))
                    }
                },
                Err(e) => return Some(Err(e.into()))
            }
        }
    }
}

/// A zero-copy "nlist" style symbol table ("stab"), including the string table
pub struct Symbols<'a> {
    data: &'a [u8],
    start: usize,
    nsyms: usize,
    // TODO: we can use an actual strtab here and tie it to symbols lifetime
    strtab: usize,
    ctx: container::Ctx,
}

impl<'a, 'b> IntoIterator for &'b Symbols<'a> {
    type Item = <SymbolIterator<'a> as Iterator>::Item;
    type IntoIter = SymbolIterator<'a>;
    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a> Symbols<'a> {
    /// Creates a new symbol table with `count` elements, from the `start` offset, using the string table at `strtab`, with a _default_ ctx.
    ////
    /// **Beware**, this will provide incorrect results if you construct this on a 32-bit mach binary, using a 64-bit machine; use `parse` instead if you want 32/64 bit support
    pub fn new(bytes: &'a [u8], start: usize, count: usize, strtab: usize) -> error::Result<Symbols<'a>> {
        let nsyms = count;
        Ok (Symbols {
            data: bytes,
            start: start,
            nsyms: nsyms,
            strtab: strtab,
            ctx: container::Ctx::default(),
        })
    }
    pub fn parse(bytes: &'a [u8], symtab: &load_command::SymtabCommand, ctx: container::Ctx) -> error::Result<Symbols<'a>> {
        // we need to normalize the strtab offset before we receive the truncated bytes in pread_with
        let strtab = symtab.stroff - symtab.symoff;
        Ok(bytes.pread_with(symtab.symoff as usize, SymbolsCtx { nsyms: symtab.nsyms as usize, strtab: strtab as usize, ctx: ctx })?)
    }

    pub fn iter(&self) -> SymbolIterator<'a> {
        SymbolIterator {
            offset: self.start as usize,
            nsyms: self.nsyms as usize,
            count: 0,
            data: self.data,
            ctx: self.ctx,
            strtab: self.strtab,
        }
    }

    /// Parses a single Nlist symbol from the binary, with its accompanying name
    pub fn get(&self, index: usize) -> ::error::Result<(&'a str, Nlist)> {
        let sym: Nlist = self.data.pread_with(self.start + (index * Nlist::size_with(&self.ctx)), self.ctx)?;
        let name = self.data.pread(self.strtab + sym.n_strx)?;
        Ok((name, sym))
    }
}

impl<'a> Debug for Symbols<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        writeln!(fmt, "Data: {} start: {:#?}, nsyms: {} strtab: {:#x}", self.data.len(), self.start, self.nsyms, self.strtab)?;
        writeln!(fmt, "Symbols: {{")?;
        for (i, res) in self.iter().enumerate() {
            match res {
                Ok((name, nlist)) => {
                    writeln!(fmt, "{: >10x} {} sect: {:#x} type: {:#02x} desc: {:#03x}", nlist.n_value, name, nlist.n_sect, nlist.n_type, nlist.n_desc)?;
                },
                Err(error) => {
                    writeln!(fmt, "  Bad symbol, index: {}, sym: {:?}", i, error)?;
                }
            }
        }
        writeln!(fmt, "}}")
    }
}
<|endoftext|>