<commit_before>import std::os;
import std::fs;
import std::os_fs;
import std::vec;
import std::map;
import std::str;
import std::uint;
import metadata::cstore;
import driver::session;
import util::filesearch;

// FIXME #721: Despite the compiler warning, test does exist and needs
// to be exported
export get_rpath_flags, test;

fn get_rpath_flags(sess: session::session, out_filename: str) -> [str] {
    // No rpath on windows
    if sess.get_targ_cfg().os == session::os_win32 {
        ret [];
    }

    log "preparing the RPATH!";

    let cwd = os::getcwd();
    let sysroot = sess.filesearch().sysroot();
    let output = out_filename;
    let libs = cstore::get_used_crate_files(sess.get_cstore());
    // We don't currently rpath native libraries, but we know
    // where rustrt is and we know every rust program needs it
    let libs = libs + [get_sysroot_absolute_rt_lib(sess)];

    let target_triple = sess.get_opts().target_triple;
    let rpaths = get_rpaths(cwd, sysroot, output, libs, target_triple);
    rpaths_to_flags(rpaths)
}

fn get_sysroot_absolute_rt_lib(sess: session::session) -> fs::path {
    let path = [sess.filesearch().sysroot()]
        + filesearch::relative_target_lib_path(
            sess.get_opts().target_triple)
        + [os::dylib_filename("rustrt")];
    check vec::is_not_empty(path);
    fs::connect_many(path)
}

fn rpaths_to_flags(rpaths: [str]) -> [str] {
    vec::map({ |rpath| #fmt("-Wl,-rpath,%s",rpath)}, rpaths)
}

fn get_rpaths(cwd: fs::path, sysroot: fs::path,
              output: fs::path, libs: [fs::path],
              target_triple: str) -> [str] {
    log #fmt("cwd: %s", cwd);
    log #fmt("sysroot: %s", sysroot);
    log #fmt("output: %s", output);
    log #fmt("libs:");
    for libpath in libs {
        log #fmt("    %s", libpath);
    }
    log #fmt("target_triple: %s", target_triple);

    // Use relative paths to the libraries. Binaries can be moved
    // as long as they maintain the relative relationship to the
    // crates they depend on.
    let rel_rpaths = get_rpaths_relative_to_output(cwd, output, libs);

    // Make backup absolute paths to the libraries. Binaries can
    // be moved as long as the crates they link against don't move.
    let abs_rpaths = get_absolute_rpaths(cwd, libs);

    // And a final backup rpath to the global library location.
    let fallback_rpaths = [get_install_prefix_rpath(target_triple)];

    fn log_rpaths(desc: str, rpaths: [str]) {
        log #fmt("%s rpaths:", desc);
        for rpath in rpaths {
            log #fmt("    %s", rpath);
        }
    }

    log_rpaths("relative", rel_rpaths);
    log_rpaths("absolute", abs_rpaths);
    log_rpaths("fallback", fallback_rpaths);

    let rpaths = rel_rpaths + abs_rpaths + fallback_rpaths;

    // Remove duplicates
    let rpaths = minimize_rpaths(rpaths);
    ret rpaths;
}

fn get_rpaths_relative_to_output(cwd: fs::path,
                                 output: fs::path,
                                 libs: [fs::path]) -> [str] {
    vec::map(bind get_rpath_relative_to_output(cwd, output, _), libs)
}

fn get_rpath_relative_to_output(cwd: fs::path,
                                output: fs::path,
                                lib: fs::path) -> str {
    "$ORIGIN" + fs::path_sep() + get_relative_to(
        get_absolute(cwd, output),
        get_absolute(cwd, lib))
}

// Find the relative path from one file to another
fn get_relative_to(abs1: fs::path, abs2: fs::path) -> fs::path {
    assert fs::path_is_absolute(abs1);
    assert fs::path_is_absolute(abs2);
    log #fmt("finding relative path from %s to %s",
             abs1, abs2);
    let normal1 = fs::normalize(abs1);
    let normal2 = fs::normalize(abs2);
    let split1 = str::split(normal1, os_fs::path_sep as u8);
    let split2 = str::split(normal2, os_fs::path_sep as u8);
    let len1 = vec::len(split1);
    let len2 = vec::len(split2);
    assert len1 > 0u;
    assert len2 > 0u;

    let max_common_path = uint::min(len1, len2) - 1u;
    let start_idx = 0u;
    while start_idx < max_common_path
        && split1[start_idx] == split2[start_idx] {
        start_idx += 1u;
    }

    let path = [];

    for each _ in uint::range(start_idx, len1 - 1u) {
        path += [".."];
    }

    path += vec::slice(split2, start_idx, len2 - 1u);

    if check vec::is_not_empty(path) {
        ret fs::connect_many(path);
    } else {
        ret ".";
    }
}

fn get_absolute_rpaths(cwd: fs::path, libs: [fs::path]) -> [str] {
    vec::map(bind get_absolute_rpath(cwd, _), libs)
}

fn get_absolute_rpath(cwd: fs::path, lib: fs::path) -> str {
    fs::dirname(get_absolute(cwd, lib))
}

fn get_absolute(cwd: fs::path, lib: fs::path) -> fs::path {
    if fs::path_is_absolute(lib) {
        lib
    } else {
        fs::connect(cwd, lib)
    }
}

fn get_install_prefix_rpath(target_triple: str) -> str {
    let install_prefix = #env("CFG_PREFIX");

    if install_prefix == "" {
        fail "rustc compiled without CFG_PREFIX environment variable";
    }

    let path = [install_prefix]
        + filesearch::relative_target_lib_path(target_triple);
    check vec::is_not_empty(path);
    fs::connect_many(path)
}

fn minimize_rpaths(rpaths: [str]) -> [str] {
    let set = map::new_str_hash::<()>();
    let minimized = [];
    for rpath in rpaths {
        if !set.contains_key(rpath) {
            minimized += [rpath];
            set.insert(rpath, ());
        }
    }
    ret minimized;
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
mod test {
    #[test]
    fn test_rpaths_to_flags() {
        let flags = rpaths_to_flags(["path1", "path2"]);
        assert flags == ["-Wl,-rpath,path1", "-Wl,-rpath,path2"];
    }

    #[test]
    fn test_get_absolute1() {
        let cwd = "/dir";
        let lib = "some/path/lib";
        let res = get_absolute(cwd, lib);
        assert res == "/dir/some/path/lib";
    }

    #[test]
    fn test_get_absolute2() {
        let cwd = "/dir";
        let lib = "/some/path/lib";
        let res = get_absolute(cwd, lib);
        assert res == "/some/path/lib";
    }

    #[test]
    fn test_prefix_rpath() {
        let res = get_install_prefix_rpath("triple");
        assert res == #env("CFG_PREFIX") + "/lib/rustc/triple/lib";
    }

    #[test]
    fn test_minimize1() {
        let res = minimize_rpaths(["rpath1", "rpath2", "rpath1"]);
        assert res == ["rpath1", "rpath2"];
    }

    #[test]
    fn test_minimize2() {
        let res = minimize_rpaths(["1a", "2", "2", "1a", "4a",
                                   "1a", "2", "3", "4a", "3"]);
        assert res == ["1a", "2", "4a", "3"];
    }

    #[test]
    fn test_relative_to1() {
        let p1 = "/usr/bin/rustc";
        let p2 = "/usr/lib/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to2() {
        let p1 = "/usr/bin/rustc";
        let p2 = "/usr/bin/../lib/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to3() {
        let p1 = "/usr/bin/whatever/rustc";
        let p2 = "/usr/lib/whatever/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../../lib/whatever";
    }

    #[test]
    fn test_relative_to4() {
        let p1 = "/usr/bin/whatever/../rustc";
        let p2 = "/usr/lib/whatever/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib/whatever";
    }

    #[test]
    fn test_relative_to5() {
        let p1 = "/usr/bin/whatever/../rustc";
        let p2 = "/usr/lib/whatever/../mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to6() {
        let p1 = "/1";
        let p2 = "/2/3";
        let res = get_relative_to(p1, p2);
        assert res == "2";
    }

    #[test]
    fn test_relative_to7() {
        let p1 = "/1/2";
        let p2 = "/3";
        let res = get_relative_to(p1, p2);
        assert res == "..";
    }

    #[test]
    fn test_relative_to8() {
        let p1 = "/home/brian/Dev/rust/build/"
            + "stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so";
        let p2 = "/home/brian/Dev/rust/build/stage2/bin/.."
            + "/lib/rustc/i686-unknown-linux-gnu/lib/libstd.so";
        let res = get_relative_to(p1, p2);
        assert res == ".";
    }

    #[test]
    fn test_rpath_relative() {
        let res = get_rpath_relative_to_output(
            "/usr", "bin/rustc", "lib/libstd.so");
        assert res == "$ORIGIN/../lib";
    }

    #[test]
    fn test_get_absolute_rpath() {
        let res = get_absolute_rpath("/usr", "lib/libstd.so");
        assert res == "/usr/lib";
    }
}
<commit_msg>Configure out rpath tests when not testing<commit_after>import std::os;
import std::fs;
import std::os_fs;
import std::vec;
import std::map;
import std::str;
import std::uint;
import metadata::cstore;
import driver::session;
import util::filesearch;

// FIXME #721: Despite the compiler warning, test does exist and needs
// to be exported
export get_rpath_flags, test;

fn get_rpath_flags(sess: session::session, out_filename: str) -> [str] {
    // No rpath on windows
    if sess.get_targ_cfg().os == session::os_win32 {
        ret [];
    }

    log "preparing the RPATH!";

    let cwd = os::getcwd();
    let sysroot = sess.filesearch().sysroot();
    let output = out_filename;
    let libs = cstore::get_used_crate_files(sess.get_cstore());
    // We don't currently rpath native libraries, but we know
    // where rustrt is and we know every rust program needs it
    let libs = libs + [get_sysroot_absolute_rt_lib(sess)];

    let target_triple = sess.get_opts().target_triple;
    let rpaths = get_rpaths(cwd, sysroot, output, libs, target_triple);
    rpaths_to_flags(rpaths)
}

fn get_sysroot_absolute_rt_lib(sess: session::session) -> fs::path {
    let path = [sess.filesearch().sysroot()]
        + filesearch::relative_target_lib_path(
            sess.get_opts().target_triple)
        + [os::dylib_filename("rustrt")];
    check vec::is_not_empty(path);
    fs::connect_many(path)
}

fn rpaths_to_flags(rpaths: [str]) -> [str] {
    vec::map({ |rpath| #fmt("-Wl,-rpath,%s",rpath)}, rpaths)
}

fn get_rpaths(cwd: fs::path, sysroot: fs::path,
              output: fs::path, libs: [fs::path],
              target_triple: str) -> [str] {
    log #fmt("cwd: %s", cwd);
    log #fmt("sysroot: %s", sysroot);
    log #fmt("output: %s", output);
    log #fmt("libs:");
    for libpath in libs {
        log #fmt("    %s", libpath);
    }
    log #fmt("target_triple: %s", target_triple);

    // Use relative paths to the libraries. Binaries can be moved
    // as long as they maintain the relative relationship to the
    // crates they depend on.
    let rel_rpaths = get_rpaths_relative_to_output(cwd, output, libs);

    // Make backup absolute paths to the libraries. Binaries can
    // be moved as long as the crates they link against don't move.
    let abs_rpaths = get_absolute_rpaths(cwd, libs);

    // And a final backup rpath to the global library location.
    let fallback_rpaths = [get_install_prefix_rpath(target_triple)];

    fn log_rpaths(desc: str, rpaths: [str]) {
        log #fmt("%s rpaths:", desc);
        for rpath in rpaths {
            log #fmt("    %s", rpath);
        }
    }

    log_rpaths("relative", rel_rpaths);
    log_rpaths("absolute", abs_rpaths);
    log_rpaths("fallback", fallback_rpaths);

    let rpaths = rel_rpaths + abs_rpaths + fallback_rpaths;

    // Remove duplicates
    let rpaths = minimize_rpaths(rpaths);
    ret rpaths;
}

fn get_rpaths_relative_to_output(cwd: fs::path,
                                 output: fs::path,
                                 libs: [fs::path]) -> [str] {
    vec::map(bind get_rpath_relative_to_output(cwd, output, _), libs)
}

fn get_rpath_relative_to_output(cwd: fs::path,
                                output: fs::path,
                                lib: fs::path) -> str {
    "$ORIGIN" + fs::path_sep() + get_relative_to(
        get_absolute(cwd, output),
        get_absolute(cwd, lib))
}

// Find the relative path from one file to another
fn get_relative_to(abs1: fs::path, abs2: fs::path) -> fs::path {
    assert fs::path_is_absolute(abs1);
    assert fs::path_is_absolute(abs2);
    log #fmt("finding relative path from %s to %s",
             abs1, abs2);
    let normal1 = fs::normalize(abs1);
    let normal2 = fs::normalize(abs2);
    let split1 = str::split(normal1, os_fs::path_sep as u8);
    let split2 = str::split(normal2, os_fs::path_sep as u8);
    let len1 = vec::len(split1);
    let len2 = vec::len(split2);
    assert len1 > 0u;
    assert len2 > 0u;

    let max_common_path = uint::min(len1, len2) - 1u;
    let start_idx = 0u;
    while start_idx < max_common_path
        && split1[start_idx] == split2[start_idx] {
        start_idx += 1u;
    }

    let path = [];

    for each _ in uint::range(start_idx, len1 - 1u) {
        path += [".."];
    }

    path += vec::slice(split2, start_idx, len2 - 1u);

    if check vec::is_not_empty(path) {
        ret fs::connect_many(path);
    } else {
        ret ".";
    }
}

fn get_absolute_rpaths(cwd: fs::path, libs: [fs::path]) -> [str] {
    vec::map(bind get_absolute_rpath(cwd, _), libs)
}

fn get_absolute_rpath(cwd: fs::path, lib: fs::path) -> str {
    fs::dirname(get_absolute(cwd, lib))
}

fn get_absolute(cwd: fs::path, lib: fs::path) -> fs::path {
    if fs::path_is_absolute(lib) {
        lib
    } else {
        fs::connect(cwd, lib)
    }
}

fn get_install_prefix_rpath(target_triple: str) -> str {
    let install_prefix = #env("CFG_PREFIX");

    if install_prefix == "" {
        fail "rustc compiled without CFG_PREFIX environment variable";
    }

    let path = [install_prefix]
        + filesearch::relative_target_lib_path(target_triple);
    check vec::is_not_empty(path);
    fs::connect_many(path)
}

fn minimize_rpaths(rpaths: [str]) -> [str] {
    let set = map::new_str_hash::<()>();
    let minimized = [];
    for rpath in rpaths {
        if !set.contains_key(rpath) {
            minimized += [rpath];
            set.insert(rpath, ());
        }
    }
    ret minimized;
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(test)]
mod test {
    #[test]
    fn test_rpaths_to_flags() {
        let flags = rpaths_to_flags(["path1", "path2"]);
        assert flags == ["-Wl,-rpath,path1", "-Wl,-rpath,path2"];
    }

    #[test]
    fn test_get_absolute1() {
        let cwd = "/dir";
        let lib = "some/path/lib";
        let res = get_absolute(cwd, lib);
        assert res == "/dir/some/path/lib";
    }

    #[test]
    fn test_get_absolute2() {
        let cwd = "/dir";
        let lib = "/some/path/lib";
        let res = get_absolute(cwd, lib);
        assert res == "/some/path/lib";
    }

    #[test]
    fn test_prefix_rpath() {
        let res = get_install_prefix_rpath("triple");
        assert res == #env("CFG_PREFIX") + "/lib/rustc/triple/lib";
    }

    #[test]
    fn test_minimize1() {
        let res = minimize_rpaths(["rpath1", "rpath2", "rpath1"]);
        assert res == ["rpath1", "rpath2"];
    }

    #[test]
    fn test_minimize2() {
        let res = minimize_rpaths(["1a", "2", "2", "1a", "4a",
                                   "1a", "2", "3", "4a", "3"]);
        assert res == ["1a", "2", "4a", "3"];
    }

    #[test]
    fn test_relative_to1() {
        let p1 = "/usr/bin/rustc";
        let p2 = "/usr/lib/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to2() {
        let p1 = "/usr/bin/rustc";
        let p2 = "/usr/bin/../lib/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to3() {
        let p1 = "/usr/bin/whatever/rustc";
        let p2 = "/usr/lib/whatever/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../../lib/whatever";
    }

    #[test]
    fn test_relative_to4() {
        let p1 = "/usr/bin/whatever/../rustc";
        let p2 = "/usr/lib/whatever/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib/whatever";
    }

    #[test]
    fn test_relative_to5() {
        let p1 = "/usr/bin/whatever/../rustc";
        let p2 = "/usr/lib/whatever/../mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to6() {
        let p1 = "/1";
        let p2 = "/2/3";
        let res = get_relative_to(p1, p2);
        assert res == "2";
    }

    #[test]
    fn test_relative_to7() {
        let p1 = "/1/2";
        let p2 = "/3";
        let res = get_relative_to(p1, p2);
        assert res == "..";
    }

    #[test]
    fn test_relative_to8() {
        let p1 = "/home/brian/Dev/rust/build/"
            + "stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so";
        let p2 = "/home/brian/Dev/rust/build/stage2/bin/.."
            + "/lib/rustc/i686-unknown-linux-gnu/lib/libstd.so";
        let res = get_relative_to(p1, p2);
        assert res == ".";
    }

    #[test]
    fn test_rpath_relative() {
        let res = get_rpath_relative_to_output(
            "/usr", "bin/rustc", "lib/libstd.so");
        assert res == "$ORIGIN/../lib";
    }

    #[test]
    fn test_get_absolute_rpath() {
        let res = get_absolute_rpath("/usr", "lib/libstd.so");
        assert res == "/usr/lib";
    }
}
<|endoftext|>


<commit_before>import std::{vec, str, int, option};
import std::option::{none, some};
import middle::ty;
import middle::ty::*;
import metadata::encoder;
import syntax::print::{pp, pprust};
import syntax::print::pprust::{path_to_str, constr_args_to_str, proto_to_str};
import pp::{word, eof, zerobreak, hardbreak};
import syntax::ast_util::ty_mach_to_str;
import syntax::ast;
import middle::ast_map;
import metadata::csearch;

fn mode_str(m: ty::mode) -> str {
    alt m {
      ast::by_ref. { "&&" }
      ast::by_val. { "+" }
      ast::by_mut_ref. { "&" }
      ast::by_move. { "-" }
      _ { "" }
    }
}

fn mode_str_1(m: ty::mode) -> str {
    alt m { ast::by_ref. { "ref" } _ { mode_str(m) } }
}

fn fn_ident_to_string(id: ast::node_id, i: ast::fn_ident) -> str {
    ret alt i { none. { "anon" + int::str(id) } some(s) { s } };
}

fn get_id_ident(cx: ctxt, id: ast::def_id) -> str {
    if id.crate != ast::local_crate {
        alt cx.ext_map.find(id) {
          some(j) { str::connect(j, "::") }
          none. { "<#" + int::str(id.crate) + ":" + int::str(id.node) + ">" }
        }
    } else {
        alt cx.items.find(id.node) {
          some(ast_map::node_item(it)) { it.ident }
          _ { fail "get_id_ident: can't find item in ast_map" }
        }
    }
}

fn ty_to_str(cx: ctxt, typ: t) -> str {
    fn fn_input_to_str(cx: ctxt, input: {mode: middle::ty::mode, ty: t}) ->
       str {
        let s = mode_str(input.mode);
        ret s + ty_to_str(cx, input.ty);
    }
    fn fn_to_str(cx: ctxt, proto: ast::proto, ident: option::t<ast::ident>,
                 inputs: [arg], output: t, cf: ast::ret_style,
                 constrs: [@constr]) -> str {
        let s = proto_to_str(proto);
        alt ident { some(i) { s += " "; s += i; } _ { } }
        s += "(";
        let strs = [];
        for a: arg in inputs { strs += [fn_input_to_str(cx, a)]; }
        s += str::connect(strs, ", ");
        s += ")";
        if struct(cx, output) != ty_nil {
            s += " -> ";
            alt cf {
              ast::noreturn. { s += "!"; }
              ast::return_ref(mut, arg) {
                s += mut ? "&!" : "&";
                if vec::len(inputs) > 1u { s += std::uint::str(arg); }
                s += ty_to_str(cx, output);
              }
              ast::return_val. { s += ty_to_str(cx, output); }
            }
        }
        s += constrs_str(constrs);
        ret s;
    }
    fn method_to_str(cx: ctxt, m: method) -> str {
        ret fn_to_str(cx, m.proto, some::<ast::ident>(m.ident), m.inputs,
                      m.output, m.cf, m.constrs) + ";";
    }
    fn field_to_str(cx: ctxt, f: field) -> str {
        ret f.ident + ": " + mt_to_str(cx, f.mt);
    }
    fn mt_to_str(cx: ctxt, m: mt) -> str {
        let mstr;
        alt m.mut {
          ast::mut. { mstr = "mutable "; }
          ast::imm. { mstr = ""; }
          ast::maybe_mut. { mstr = "mutable? "; }
        }
        ret mstr + ty_to_str(cx, m.ty);
    }
    alt cname(cx, typ) { some(cs) { ret cs; } _ { } }
    ret alt struct(cx, typ) {
          ty_native(_) { "native" }
          ty_nil. { "()" }
          ty_bot. { "_|_" }
          ty_bool. { "bool" }
          ty_int. { "int" }
          ty_float. { "float" }
          ty_uint. { "uint" }
          ty_machine(tm) { ty_mach_to_str(tm) }
          ty_char. { "char" }
          ty_str. { "str" }
          ty_box(tm) { "@" + mt_to_str(cx, tm) }
          ty_uniq(tm) { "~" + mt_to_str(cx, tm) }
          ty_vec(tm) { "[" + mt_to_str(cx, tm) + "]" }
          ty_type. { "type" }
          ty_rec(elems) {
            let strs: [str] = [];
            for fld: field in elems { strs += [field_to_str(cx, fld)]; }
            "{" + str::connect(strs, ",") + "}"
          }
          ty_tup(elems) {
            let strs = [];
            for elem in elems { strs += [ty_to_str(cx, elem)]; }
            "(" + str::connect(strs, ",") + ")"
          }
          ty_tag(id, tps) {
            let s = get_id_ident(cx, id);
            if vec::len::<t>(tps) > 0u {
                let strs: [str] = [];
                for typ: t in tps { strs += [ty_to_str(cx, typ)]; }
                s += "[" + str::connect(strs, ",") + "]";
            }
            s
          }
          ty_fn(proto, inputs, output, cf, constrs) {
            fn_to_str(cx, proto, none, inputs, output, cf, constrs)
          }
          ty_native_fn(_, inputs, output) {
            fn_to_str(cx, ast::proto_bare, none, inputs, output,
                      ast::return_val, [])
          }
          ty_obj(meths) {
            let strs = [];
            for m: method in meths { strs += [method_to_str(cx, m)]; }
            "obj {\n\t" + str::connect(strs, "\n\t") + "\n}"
          }
          ty_res(id, _, _) { get_id_ident(cx, id) }
          ty_var(v) { "<T" + int::str(v) + ">" }
          ty_param(id, _) {
            "'" + str::unsafe_from_bytes([('a' as u8) + (id as u8)])
          }
          _ { ty_to_short_str(cx, typ) }
        }
}

fn ty_to_short_str(cx: ctxt, typ: t) -> str {
    let s = encoder::encoded_ty(cx, typ);
    if str::byte_len(s) >= 32u { s = str::substr(s, 0u, 32u); }
    ret s;
}

fn constr_to_str(c: @constr) -> str {
    ret path_to_str(c.node.path) +
            pprust::constr_args_to_str(pprust::uint_to_str, c.node.args);
}

fn constrs_str(constrs: [@constr]) -> str {
    let s = "";
    let colon = true;
    for c: @constr in constrs {
        if colon { s += " : "; colon = false; } else { s += ", "; }
        s += constr_to_str(c);
    }
    ret s;
}

fn ty_constr_to_str<Q>(c: @ast::spanned<ast::constr_general_<ast::path, Q>>)
   -> str {
    ret path_to_str(c.node.path) +
            constr_args_to_str::<ast::path>(path_to_str, c.node.args);
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Fix printing of parameterized tag types in ppaux<commit_after>import std::{vec, str, int, option};
import std::option::{none, some};
import middle::ty;
import middle::ty::*;
import metadata::encoder;
import syntax::print::{pp, pprust};
import syntax::print::pprust::{path_to_str, constr_args_to_str, proto_to_str};
import pp::{word, eof, zerobreak, hardbreak};
import syntax::ast_util::ty_mach_to_str;
import syntax::ast;
import middle::ast_map;
import metadata::csearch;

fn mode_str(m: ty::mode) -> str {
    alt m {
      ast::by_ref. { "&&" }
      ast::by_val. { "+" }
      ast::by_mut_ref. { "&" }
      ast::by_move. { "-" }
      _ { "" }
    }
}

fn mode_str_1(m: ty::mode) -> str {
    alt m { ast::by_ref. { "ref" } _ { mode_str(m) } }
}

fn fn_ident_to_string(id: ast::node_id, i: ast::fn_ident) -> str {
    ret alt i { none. { "anon" + int::str(id) } some(s) { s } };
}

fn get_id_ident(cx: ctxt, id: ast::def_id) -> str {
    if id.crate != ast::local_crate {
        alt cx.ext_map.find(id) {
          some(j) { str::connect(j, "::") }
          none. { "<#" + int::str(id.crate) + ":" + int::str(id.node) + ">" }
        }
    } else {
        alt cx.items.find(id.node) {
          some(ast_map::node_item(it)) { it.ident }
          _ { fail "get_id_ident: can't find item in ast_map" }
        }
    }
}

fn ty_to_str(cx: ctxt, typ: t) -> str {
    fn fn_input_to_str(cx: ctxt, input: {mode: middle::ty::mode, ty: t}) ->
       str {
        let s = mode_str(input.mode);
        ret s + ty_to_str(cx, input.ty);
    }
    fn fn_to_str(cx: ctxt, proto: ast::proto, ident: option::t<ast::ident>,
                 inputs: [arg], output: t, cf: ast::ret_style,
                 constrs: [@constr]) -> str {
        let s = proto_to_str(proto);
        alt ident { some(i) { s += " "; s += i; } _ { } }
        s += "(";
        let strs = [];
        for a: arg in inputs { strs += [fn_input_to_str(cx, a)]; }
        s += str::connect(strs, ", ");
        s += ")";
        if struct(cx, output) != ty_nil {
            s += " -> ";
            alt cf {
              ast::noreturn. { s += "!"; }
              ast::return_ref(mut, arg) {
                s += mut ? "&!" : "&";
                if vec::len(inputs) > 1u { s += std::uint::str(arg); }
                s += ty_to_str(cx, output);
              }
              ast::return_val. { s += ty_to_str(cx, output); }
            }
        }
        s += constrs_str(constrs);
        ret s;
    }
    fn method_to_str(cx: ctxt, m: method) -> str {
        ret fn_to_str(cx, m.proto, some::<ast::ident>(m.ident), m.inputs,
                      m.output, m.cf, m.constrs) + ";";
    }
    fn field_to_str(cx: ctxt, f: field) -> str {
        ret f.ident + ": " + mt_to_str(cx, f.mt);
    }
    fn mt_to_str(cx: ctxt, m: mt) -> str {
        let mstr;
        alt m.mut {
          ast::mut. { mstr = "mutable "; }
          ast::imm. { mstr = ""; }
          ast::maybe_mut. { mstr = "mutable? "; }
        }
        ret mstr + ty_to_str(cx, m.ty);
    }
    alt cname(cx, typ) { some(cs) { ret cs; } _ { } }
    ret alt struct(cx, typ) {
          ty_native(_) { "native" }
          ty_nil. { "()" }
          ty_bot. { "_|_" }
          ty_bool. { "bool" }
          ty_int. { "int" }
          ty_float. { "float" }
          ty_uint. { "uint" }
          ty_machine(tm) { ty_mach_to_str(tm) }
          ty_char. { "char" }
          ty_str. { "str" }
          ty_box(tm) { "@" + mt_to_str(cx, tm) }
          ty_uniq(tm) { "~" + mt_to_str(cx, tm) }
          ty_vec(tm) { "[" + mt_to_str(cx, tm) + "]" }
          ty_type. { "type" }
          ty_rec(elems) {
            let strs: [str] = [];
            for fld: field in elems { strs += [field_to_str(cx, fld)]; }
            "{" + str::connect(strs, ",") + "}"
          }
          ty_tup(elems) {
            let strs = [];
            for elem in elems { strs += [ty_to_str(cx, elem)]; }
            "(" + str::connect(strs, ",") + ")"
          }
          ty_tag(id, tps) {
            let s = get_id_ident(cx, id);
            if vec::len::<t>(tps) > 0u {
                let strs: [str] = [];
                for typ: t in tps { strs += [ty_to_str(cx, typ)]; }
                s += "<" + str::connect(strs, ",") + ">";
            }
            s
          }
          ty_fn(proto, inputs, output, cf, constrs) {
            fn_to_str(cx, proto, none, inputs, output, cf, constrs)
          }
          ty_native_fn(_, inputs, output) {
            fn_to_str(cx, ast::proto_bare, none, inputs, output,
                      ast::return_val, [])
          }
          ty_obj(meths) {
            let strs = [];
            for m: method in meths { strs += [method_to_str(cx, m)]; }
            "obj {\n\t" + str::connect(strs, "\n\t") + "\n}"
          }
          ty_res(id, _, _) { get_id_ident(cx, id) }
          ty_var(v) { "<T" + int::str(v) + ">" }
          ty_param(id, _) {
            "'" + str::unsafe_from_bytes([('a' as u8) + (id as u8)])
          }
          _ { ty_to_short_str(cx, typ) }
        }
}

fn ty_to_short_str(cx: ctxt, typ: t) -> str {
    let s = encoder::encoded_ty(cx, typ);
    if str::byte_len(s) >= 32u { s = str::substr(s, 0u, 32u); }
    ret s;
}

fn constr_to_str(c: @constr) -> str {
    ret path_to_str(c.node.path) +
            pprust::constr_args_to_str(pprust::uint_to_str, c.node.args);
}

fn constrs_str(constrs: [@constr]) -> str {
    let s = "";
    let colon = true;
    for c: @constr in constrs {
        if colon { s += " : "; colon = false; } else { s += ", "; }
        s += constr_to_str(c);
    }
    ret s;
}

fn ty_constr_to_str<Q>(c: @ast::spanned<ast::constr_general_<ast::path, Q>>)
   -> str {
    ret path_to_str(c.node.path) +
            constr_args_to_str::<ast::path>(path_to_str, c.node.args);
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>#![allow(dead_code)]
extern crate toml;
extern crate irc;
extern crate debug;
extern crate serialize;

use std::path::Path;
use std::io::fs::File;
use std::os::args_as_bytes;

use toml::Parser;

use irc::{
    IrcConnection,
    IrcEventMessage,
    IrcEventBundle,
    IrcEventWatcherResponse,
};

#[deriving(Decodable, Encodable)]
struct BotConfig {
    server_host: String,
    server_port: u16,
    nickname: String,
    channels: Vec<String>
}

fn parse_botconfig() -> Option<BotConfig> {
    let filename = Path::new(match args_as_bytes().as_slice() {
        [] => fail!("impossible"),
        [_] => return None,
        [_, ref filename] => filename.clone(),
        [_, ref filename, ..rest] => filename.clone()
    });
    let mut file = match File::open(&filename) {
        Ok(file) => file,
        Err(err) => fail!("{}", err)
    };
    let contents = match file.read_to_string() {
        Ok(contents) => contents,
        Err(err) => fail!("{}", err)
    };
    let mut parser = Parser::new(contents.as_slice());
    let table = match parser.parse() {
        Some(table) => {
            let core_key = String::from_str("core");
            match table.find(&core_key) {
                Some(value) => value.clone(),
                None => fail!("failed to parse in some way.")
            }
        }
        None => fail!("failed to parse in some way.")
    };
    toml::decode::<BotConfig>(table)
}

fn main() {
    let botconfig = match parse_botconfig() {
        Some(config) => config,
        None => fail!("bad config")
    };

    let conn = IrcConnection::new(
        botconfig.server_host.as_slice(),
        botconfig.server_port);

    let (mut conn, event_queue) = match conn {
        Ok(stream) => stream,
        Err(err) => fail!("{}", err)
    };
    let mut nick = botconfig.nickname.clone();

    loop {
        println!("trying nick {}", nick.as_slice());
        match conn.register(nick.as_slice()) {
            Ok(_) => {
                println!("ok, connected as {}", nick.as_slice());
                break;
            }
            Err(err) => {
                if err.should_pick_new_nickname() {
                    nick = nick.append("`");
                } else {
                    fail!("{:?}", err)
                }
            }
        };
    }

    for channel in botconfig.channels.iter() {
        println!("joining {}...", channel);
        match conn.join(channel.as_slice()) {
            Ok(res) => {
                println!("succeeded in joining {}, got {} nicks",
                    res.channel.as_slice(), res.nicks.len());
            },
            Err(err) => {
                println!("join error: {:?}", err);
                fail!("failed to join channel.. dying");
            }
        }
    }

    loop {
        match event_queue.recv() {
            IrcEventMessage(message) => {
                println!("RX: {}", message);
                if message.get_command().as_slice() == "PING" {
                    let response = format!("PONG :{}\n", message.get_arg(0));
                    println!("TX: {}", response.as_slice());
                    conn.write_str(response.as_slice())
                }
            },
            IrcEventBundle(event) => {
                println!("got bundle back: {}", event.pretty_print());
            },
            IrcEventWatcherResponse(watcher) => {
                println!("got watcher back: {}", watcher.pretty_print());
            }
        }
    }
}
<commit_msg>Slice mapping can use [..] to match rest<commit_after>#![allow(dead_code)]
extern crate toml;
extern crate irc;
extern crate debug;
extern crate serialize;

use std::path::Path;
use std::io::fs::File;
use std::os::args_as_bytes;

use toml::Parser;

use irc::{
    IrcConnection,
    IrcEventMessage,
    IrcEventBundle,
    IrcEventWatcherResponse,
};

#[deriving(Decodable, Encodable)]
struct BotConfig {
    server_host: String,
    server_port: u16,
    nickname: String,
    channels: Vec<String>
}

fn parse_botconfig() -> Option<BotConfig> {
    let filename = Path::new(match args_as_bytes().as_slice() {
        [] => fail!("impossible"),
        [_] => return None,
        [_, ref filename] => filename.clone(),
        [_, ref filename, ..] => filename.clone()
    });
    let mut file = match File::open(&filename) {
        Ok(file) => file,
        Err(err) => fail!("{}", err)
    };
    let contents = match file.read_to_string() {
        Ok(contents) => contents,
        Err(err) => fail!("{}", err)
    };
    let mut parser = Parser::new(contents.as_slice());
    let table = match parser.parse() {
        Some(table) => {
            let core_key = String::from_str("core");
            match table.find(&core_key) {
                Some(value) => value.clone(),
                None => fail!("failed to parse in some way.")
            }
        }
        None => fail!("failed to parse in some way.")
    };
    toml::decode::<BotConfig>(table)
}

fn main() {
    let botconfig = match parse_botconfig() {
        Some(config) => config,
        None => fail!("bad config")
    };

    let conn = IrcConnection::new(
        botconfig.server_host.as_slice(),
        botconfig.server_port);

    let (mut conn, event_queue) = match conn {
        Ok(stream) => stream,
        Err(err) => fail!("{}", err)
    };
    let mut nick = botconfig.nickname.clone();

    loop {
        println!("trying nick {}", nick.as_slice());
        match conn.register(nick.as_slice()) {
            Ok(_) => {
                println!("ok, connected as {}", nick.as_slice());
                break;
            }
            Err(err) => {
                if err.should_pick_new_nickname() {
                    nick = nick.append("`");
                } else {
                    fail!("{:?}", err)
                }
            }
        };
    }

    for channel in botconfig.channels.iter() {
        println!("joining {}...", channel);
        match conn.join(channel.as_slice()) {
            Ok(res) => {
                println!("succeeded in joining {}, got {} nicks",
                    res.channel.as_slice(), res.nicks.len());
            },
            Err(err) => {
                println!("join error: {:?}", err);
                fail!("failed to join channel.. dying");
            }
        }
    }

    loop {
        match event_queue.recv() {
            IrcEventMessage(message) => {
                println!("RX: {}", message);
                if message.get_command().as_slice() == "PING" {
                    let response = format!("PONG :{}\n", message.get_arg(0));
                    println!("TX: {}", response.as_slice());
                    conn.write_str(response.as_slice())
                }
            },
            IrcEventBundle(event) => {
                println!("got bundle back: {}", event.pretty_print());
            },
            IrcEventWatcherResponse(watcher) => {
                println!("got watcher back: {}", watcher.pretty_print());
            }
        }
    }
}
<|endoftext|>


<commit_before>use serde;
use super::{ActionType, ExecCondition};

#[cfg(test)]
mod test;

impl serde::de::Deserialize for ActionType {
    fn deserialize<D>(deserializer: &mut D) -> Result<ActionType, D::Error>
        where D: serde::de::Deserializer
    {
        enum Field {
            Message,
        }

        impl serde::de::Deserialize for Field {
            #[inline]
            fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
                where D: serde::de::Deserializer
            {
                struct FieldVisitor;

                impl serde::de::Visitor for FieldVisitor {
                    type Value = Field;

                    fn visit_str<E>(&mut self, value: &str) -> Result<Field, E>
                        where E: serde::de::Error
                    {
                        match value {
                            "message" => Ok(Field::Message),
                            _ => Err(serde::de::Error::unknown_field(value)),
                        }
                    }
                }

                deserializer.visit(FieldVisitor)
            }
        }

        struct Visitor;

        impl serde::de::EnumVisitor for Visitor {
            type Value = ActionType;

            fn visit<V>(&mut self, mut visitor: V) -> Result<ActionType, V::Error>
                where V: serde::de::VariantVisitor
            {
                match try!(visitor.visit_variant()) {
                    Field::Message => {
                        let value = try!(visitor.visit_newtype());
                        Ok(ActionType::Message(value))
                    }
                }
            }
        }

        const VARIANTS: &'static [&'static str] = &["message"];

        deserializer.visit_enum("ActionType", VARIANTS, Visitor)
    }
}

impl serde::de::Deserialize for ExecCondition {
    fn deserialize<D>(deserializer: &mut D) -> Result<ExecCondition, D::Error>
        where D: serde::de::Deserializer
    {
        enum Field {
            OnOpened,
            OnClosed,
        }

        impl serde::de::Deserialize for Field {
            fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
                where D: serde::de::Deserializer
            {
                struct FieldVisitor;

                impl serde::de::Visitor for FieldVisitor {
                    type Value = Field;

                    fn visit_str<E>(&mut self, value: &str) -> Result<Field, E>
                        where E: serde::de::Error
                    {
                        match value {
                            "on_opened" => Ok(Field::OnOpened),
                            "on_closed" => Ok(Field::OnClosed),
                            _ => {
                                Err(serde::de::Error::syntax(&format!("Unexpected field: {}",
                                                                      value)))
                            }
                        }
                    }
                }

                deserializer.visit(FieldVisitor)
            }
        }

        struct ExecConditionVisitor;

        impl serde::de::Visitor for ExecConditionVisitor {
            type Value = ExecCondition;

            fn visit_map<V>(&mut self, mut visitor: V) -> Result<ExecCondition, V::Error>
                where V: serde::de::MapVisitor
            {
                let mut condition: ExecCondition = Default::default();

                while let Some(field) = try!(visitor.visit_key()) {
                    match field {
                        Field::OnOpened => condition.on_opened = try!(visitor.visit_value()),
                        Field::OnClosed => condition.on_closed = try!(visitor.visit_value()),
                    }
                }

                try!(visitor.end());

                Ok(condition)
            }
        }
        deserializer.visit_struct("ExecCondition", &[], ExecConditionVisitor)
    }
}
<commit_msg>ExecCondition: suppress warning in deser code<commit_after>use serde;
use super::{ActionType, ExecCondition};

#[cfg(test)]
mod test;

impl serde::de::Deserialize for ActionType {
    fn deserialize<D>(deserializer: &mut D) -> Result<ActionType, D::Error>
        where D: serde::de::Deserializer
    {
        enum Field {
            Message,
        }

        impl serde::de::Deserialize for Field {
            #[inline]
            fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
                where D: serde::de::Deserializer
            {
                struct FieldVisitor;

                impl serde::de::Visitor for FieldVisitor {
                    type Value = Field;

                    fn visit_str<E>(&mut self, value: &str) -> Result<Field, E>
                        where E: serde::de::Error
                    {
                        match value {
                            "message" => Ok(Field::Message),
                            _ => Err(serde::de::Error::unknown_field(value)),
                        }
                    }
                }

                deserializer.visit(FieldVisitor)
            }
        }

        struct Visitor;

        impl serde::de::EnumVisitor for Visitor {
            type Value = ActionType;

            fn visit<V>(&mut self, mut visitor: V) -> Result<ActionType, V::Error>
                where V: serde::de::VariantVisitor
            {
                match try!(visitor.visit_variant()) {
                    Field::Message => {
                        let value = try!(visitor.visit_newtype());
                        Ok(ActionType::Message(value))
                    }
                }
            }
        }

        const VARIANTS: &'static [&'static str] = &["message"];

        deserializer.visit_enum("ActionType", VARIANTS, Visitor)
    }
}

impl serde::de::Deserialize for ExecCondition {
    fn deserialize<D>(deserializer: &mut D) -> Result<ExecCondition, D::Error>
        where D: serde::de::Deserializer
    {
        // the have the same On prefix
        #[allow(enum_variant_names)]
        enum Field {
            OnOpened,
            OnClosed,
        }

        impl serde::de::Deserialize for Field {
            fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
                where D: serde::de::Deserializer
            {
                struct FieldVisitor;

                impl serde::de::Visitor for FieldVisitor {
                    type Value = Field;

                    fn visit_str<E>(&mut self, value: &str) -> Result<Field, E>
                        where E: serde::de::Error
                    {
                        match value {
                            "on_opened" => Ok(Field::OnOpened),
                            "on_closed" => Ok(Field::OnClosed),
                            _ => {
                                Err(serde::de::Error::syntax(&format!("Unexpected field: {}",
                                                                      value)))
                            }
                        }
                    }
                }

                deserializer.visit(FieldVisitor)
            }
        }

        struct ExecConditionVisitor;

        impl serde::de::Visitor for ExecConditionVisitor {
            type Value = ExecCondition;

            fn visit_map<V>(&mut self, mut visitor: V) -> Result<ExecCondition, V::Error>
                where V: serde::de::MapVisitor
            {
                let mut condition: ExecCondition = Default::default();

                while let Some(field) = try!(visitor.visit_key()) {
                    match field {
                        Field::OnOpened => condition.on_opened = try!(visitor.visit_value()),
                        Field::OnClosed => condition.on_closed = try!(visitor.visit_value()),
                    }
                }

                try!(visitor.end());

                Ok(condition)
            }
        }
        deserializer.visit_struct("ExecCondition", &[], ExecConditionVisitor)
    }
}
<|endoftext|>


<commit_before>use config::{AhabConfig, HostId};
use internal::network::{HostAddr};
use internal::process::{Process, HostAddr, ProcessHelper};

use collections::hashmap::{HashMap, HashSet};
use collections::treemap::{TreeMap};
use serialize::{base64, Decodable, Decoder, Encodable, Encoder};
use serialize::base64::{FromBase64, ToBase64};
use std::cmp::{max};
use sync::{Arc, RWLock};

macro_rules! match_until (
  ($e:expr, $p:ident($($lhs:pat),*) => $rhs:expr) => ({
    let mut m;
    loop {
      m = $e;
      match m {
        $p(..) => break,
        _ => (),
      }
    }
    match m {
      $p($($lhs),*) => $rhs,
      _ => fail!(),
    }
  })
)

pub type Epoch = u64;

#[deriving(Clone, TotalEq, TotalOrd)]
#[deriving(Decodable, Encodable)]
pub struct TxnId {
  epoch: Epoch,
  tick: u64,
}

impl TxnId {
  pub fn lower_bound() -> TxnId {
    TxnId{epoch: 0, tick: 0}
  }
}

impl Eq for TxnId {
  fn eq(&self, other: &TxnId) -> bool {
    self.epoch == other.epoch && self.tick == other.tick
  }
}

impl Ord for TxnId {
  fn lt(&self, other: &TxnId) -> bool {
    self.epoch < other.epoch || (self.epoch == other.epoch && self.tick < other.tick)
  }
}

#[deriving(Clone)]
#[deriving(Decodable, Encodable)]
pub enum TxnOp {
  Put(TxnPutOp),
  Delete(TxnDeleteOp),
}

#[deriving(Clone)]
pub struct TxnPutOp {
  key: ~str,
  value: ~[u8],
}

impl<E, S: Encoder<E>> Encodable<S, E> for TxnPutOp {
  fn encode(&self, s: &mut S) -> Result<(), E> {
    match s.emit_str(self.key) {
      Ok(()) => (),
      Err(e) => return Err(e),
    }
    let value: &[u8] = self.value;
    match s.emit_str(value.to_base64(base64::STANDARD)) {
      Ok(()) => (),
      Err(e) => return Err(e),
    }
    Ok(())
  }
}

impl<E, D: Decoder<E>> Decodable<D, E> for TxnPutOp {
  fn decode(d: &mut D) -> Result<TxnPutOp, E> {
    // FIXME handle errors.
    let key = d.read_str().ok().unwrap();
    let value = d.read_str().ok().unwrap()
        .from_base64().ok().unwrap();
    let op = TxnPutOp{key: key, value: value};
    Ok(op)
  }
}

#[deriving(Clone)]
#[deriving(Decodable, Encodable)]
pub struct TxnDeleteOp {
  key: ~str,
}

#[deriving(Clone)]
#[deriving(Decodable, Encodable)]
pub struct Txn {
  xid: TxnId,
  ops: Vec<TxnOp>,
}

impl Txn {
  pub fn acceptable(&self) -> bool {
    true
  }
}

#[deriving(Clone)]
#[deriving(Decodable, Encodable)]
pub enum ProtocolMsg {
  Heartbeat,
  Timeout,
  // Discovery phase.
  CurrentEpoch(Epoch),
  NewEpoch(Epoch, TxnId),
  AckEpoch(Epoch, TxnId),
  ReqEpochHistory(Epoch, TxnId),
  AckEpochHistory(Epoch, Vec<Txn>),
  // Synchronization phase.
  NewMaster(Epoch, Vec<Txn>),
  AckMaster(Epoch),
  CommitMaster(Epoch),
  // Broadcast phase.
  Propose(Epoch, Txn),
  Ack(Epoch, TxnId),
  Commit(Epoch, TxnId),
}

enum ProtocolPhase {
  Discovery,
  Synchronization,
  Broadcast,
}

enum ProtocolState {
  Electing,
  Following,
  Leading,
}

pub struct SharedState {
  history: Vec<Txn>,
}

pub struct MasterProcess {
  helper: ProcessHelper,
  config: Arc<AhabConfig>,
  phase: ProtocolPhase,
  quorum: HashSet<HostAddr>,
  epoch: Epoch,
  shared: Arc<RWLock<SharedState>>,
}

impl MasterProcess {
  pub fn new(config: Arc<AhabConfig>) -> MasterProcess {
    MasterProcess{
      helper: ProcessHelper::new(),
      config: config,
      phase: Discovery,
      quorum: HashSet::new(),
      epoch: 0,
      shared: Arc::new(RWLock::new(SharedState{history: Vec::new()})),
    }
  }

  pub fn quorum_min_size(&self) -> uint {
    3
  }

  pub fn quorum_max_size(&self) -> uint {
    5
  }
}

impl Process<ProtocolMsg> for MasterProcess {
  fn send(&self, dest: &HostAddr, msg: ProtocolMsg) {
  }

  fn recv(&self) -> (HostAddr, ProtocolMsg) {
    self.helper.recv();
    (HostAddr::default(), Heartbeat)
  }

  fn process(&mut self) {
    let identity = HostAddr::default();
    match self.phase {
      Discovery => {
        // Receive from a quorum of followers CurrentEpoch(e).
        let mut quorum_epochs = HashMap::<HostAddr, Epoch>::new();
        loop {
          match self.recv() {
            (addr, msg) => match msg {
              CurrentEpoch(e) => {
                self.quorum.insert(addr);
                quorum_epochs.insert(addr, e);
                if self.quorum.len() == self.quorum_max_size() {
                  break;
                }
              },
              Timeout => {
                if self.quorum.len() >= self.quorum_min_size() {
                  break;
                }
              },
              _ => (),
            },
          }
        }

        // Send to quorum NewEpoch(e') s.t. e' = max(e received from quorum) + 1.
        self.epoch = {
          let mut sup_epoch: Epoch = 0;
          for (_, &e) in quorum_epochs.iter() {
            sup_epoch = max(sup_epoch, e);
          }
          sup_epoch + 1
        };
        assert!(self.epoch != 0);
        for (addr, _) in quorum_epochs.iter() {
          // FIXME read txn history from master process?
          self.send(addr, NewEpoch(self.epoch, TxnId::lower_bound()));
        }

        // Receive from quorum AckEpoch(m, diff).
        let mut quorum_xids = HashMap::<HostAddr, TxnId>::new();
        loop {
          match self.recv() {
            (addr, msg) => match msg {
              AckEpoch(e, xid) => {
                if self.quorum.contains(&addr) {
                  quorum_xids.insert(addr, xid);
                }
                if quorum_xids.len() == self.quorum_max_size() {
                  break;
                }
              },
              Timeout => {
                if quorum_xids.len() >= self.quorum_min_size() {
                  break;
                }
              },
              _ => (),
            }
          }
        }

        // Select a follower in quorum and its diff.
        let chosen_host = {
          let mut chosen_host = identity;
          let mut sup_xid = TxnId::lower_bound();
          for (&addr, &xid) in quorum_xids.iter() {
            if xid > sup_xid {
              chosen_host = addr;
              sup_xid = xid;
            }
          }
          chosen_host
        };

        // (Send to chosen follower ReqEpochHistory(e', xid').)
        let last_xid = {
          let shared = self.shared.read();
          match shared.history.last() {
            Some(txn) => txn.xid,
            None => TxnId::lower_bound(),
          }
        };
        self.send(&chosen_host, ReqEpochHistory(self.epoch, last_xid));

        // (Receive from chosen follower AckEpochHistory(e', diff).)
        let (e, diff) = match_until!(self.recv_from(&chosen_host), AckEpochHistory(e, diff) => (e, diff));
        assert!(e == self.epoch);

        // Transition to Synchronization phase.
        self.phase = Synchronization;
      },
      Synchronization => {
        // Send to quorum NewMaster(e', diff).
        // Receive from quorum AckMaster(e', diff), send to quorum
        // CommitMaster(e', diff), and transition to Broadcast phase.
      },
      Broadcast => {
        // Receive from primary process a proposed txn.
        // Send to quorum Propose(e', txn).
        // Receive from quorum Ack(e', txn).
        // Send to all followers Commit(e', txn).
      },
    }
  }
}

pub struct SlaveProcess {
  helper: ProcessHelper,
  config: Arc<AhabConfig>,
  phase: ProtocolPhase,
  last_epoch_prop: Epoch,
  last_master_prop: Epoch,
  accepted_txns: TreeMap<TxnId, Txn>,
  committing_txns: TreeMap<TxnId, Txn>,
  shared: Arc<RWLock<SharedState>>,
}

impl SlaveProcess {
  pub fn new(config: Arc<AhabConfig>) -> SlaveProcess {
    SlaveProcess{
      helper: ProcessHelper::new(),
      config: config,
      phase: Discovery,
      last_epoch_prop: 0,
      last_master_prop: 0,
      accepted_txns: TreeMap::new(),
      committing_txns: TreeMap::new(),
      //history: Vec::new(),
      shared: Arc::new(RWLock::new(SharedState{history: Vec::new()})),
    }
  }

  pub fn infer_master(&self) -> HostId {
    HostId(0)
  }
}

impl Process<ProtocolMsg> for SlaveProcess {
  fn send(&self, dest: &HostAddr, msg: ProtocolMsg) {
  }

  fn recv(&self) -> (HostAddr, ProtocolMsg) {
    self.helper.recv();
    (HostAddr::default(), Heartbeat)
  }

  fn process(&mut self) {
    let identity = HostId(0);
    let leader = HostAddr::default();
    loop {
      match self.phase {
        Discovery => {
          // Send to leader CurrentEpoch(self.last_epoch_prop).
          self.send(&leader, CurrentEpoch(self.last_epoch_prop));
          // Receive from leader NewEpoch(e).
          let (e, last_xid) = match_until!(self.recv_from(&leader), NewEpoch(e, xid) => (e, xid));
          // If self.last_epoch_prop < e, then set self.last_epoch_prop = e, send to
          // leader AckEpoch(self.last_master_prop, diff), and transition to
          // Synchronization phase.
          if self.last_epoch_prop < e {
            self.last_epoch_prop = e;
            self.send(&leader, AckEpoch(self.last_master_prop, TxnId::lower_bound())); // FIXME
            self.phase = Synchronization;
          }
        },
        Synchronization => {
          // Receive from leader NewMaster(e, diff).
          // If self.last_epoch_prop != e, then transition to Discovery phase.
          let (e, diff) = match_until!(self.recv_from(&leader), NewMaster(e, diff) => (e, diff));
          if e != self.last_epoch_prop {
            self.phase = Discovery;
            continue;
          }

          // Atomically:
          // 1. set self.last_epoch_prop = e,
          // 2. for each txn in diff, accept txn.
          // (If failure, then transition to Discovery phase.)
          let accepted_txns = {
            let mut accepted_txns = Vec::<Txn>::new();
            let mut diff_accepted = true;
            for txn in diff.move_iter() {
              if txn.acceptable() {
                accepted_txns.push(txn);
              } else {
                diff_accepted = false;
                break;
              }
            }
            if diff_accepted {
              self.last_master_prop = e;
            } else {
              self.phase = Discovery;
              continue;
            }
            accepted_txns
          };

          // Send to leader AckMaster.
          self.send(&leader, AckMaster(self.last_epoch_prop));

          // Receive from leader CommitMaster.
          // (If self.last_epoch_prop != e, then transition to Discovery phase.)
          let e = match_until!(self.recv_from(&leader), CommitMaster(e) => e);
          if e != self.last_epoch_prop {
            self.phase = Discovery;
            continue;
          }

          // For each accepted txn, deliver txn.
          {
            let mut shared = self.shared.write();
            for txn in accepted_txns.move_iter() {
              shared.history.push(txn);
            }
          }

          // Transition to Broadcast phase.
          // If self.infer_master() is itself, invoke self.ready(e).
          self.phase = Broadcast;
          if identity == self.infer_master() {
            // FIXME
          }
        },
        Broadcast => {
          match self.recv_from(&leader) {
            Propose(e, txn) => {
              // Accept proposed txns from leader and append each txn to
              // self.history.
              self.accepted_txns.insert(txn.xid, txn);
            },
            Commit(e, xid) => {
              // Upon receiving from leader Commit(e, txn), and when all txn'
              // s.t. txn' < txn are committed, commit txn.
              match self.accepted_txns.pop(&xid) {
                Some(txn) => {
                  self.committing_txns.insert(xid, txn);
                },
                None => (),
              }
              let mut to_commit_xids = Vec::<TxnId>::new();
              'commit_all: for (&xid, txn) in self.committing_txns.iter() {
                for (&acc_xid, acc_txn) in self.accepted_txns.iter() {
                  if acc_xid < xid {
                    break 'commit_all;
                  } else {
                    break;
                  }
                }
                to_commit_xids.push(xid);
              }
              {
                let mut shared = self.shared.write();
                for xid in to_commit_xids.iter() {
                  let txn = self.committing_txns.pop(xid).unwrap();
                  shared.history.push(txn);
                }
              }
            },
            _ => (),
          }
        },
      }
    }
  }
}
<commit_msg>Shared state between master and slave processes.<commit_after>use config::{AhabConfig, HostId};
use internal::network::{HostAddr};
use internal::process::{Process, HostAddr, ProcessHelper};

use collections::hashmap::{HashMap, HashSet};
use collections::treemap::{TreeMap};
use serialize::{base64, Decodable, Decoder, Encodable, Encoder};
use serialize::base64::{FromBase64, ToBase64};
use std::cmp::{max};
use sync::{Arc, RWLock};

macro_rules! match_until (
  ($e:expr, $p:ident($($lhs:pat),*) => $rhs:expr) => ({
    let mut m;
    loop {
      m = $e;
      match m {
        $p(..) => break,
        _ => (),
      }
    }
    match m {
      $p($($lhs),*) => $rhs,
      _ => fail!(),
    }
  })
)

pub type Epoch = u64;

#[deriving(Clone, TotalEq, TotalOrd)]
#[deriving(Decodable, Encodable)]
pub struct TxnId {
  epoch: Epoch,
  tick: u64,
}

impl TxnId {
  pub fn lower_bound() -> TxnId {
    TxnId{epoch: 0, tick: 0}
  }
}

impl Eq for TxnId {
  fn eq(&self, other: &TxnId) -> bool {
    self.epoch == other.epoch && self.tick == other.tick
  }
}

impl Ord for TxnId {
  fn lt(&self, other: &TxnId) -> bool {
    self.epoch < other.epoch || (self.epoch == other.epoch && self.tick < other.tick)
  }
}

#[deriving(Clone)]
#[deriving(Decodable, Encodable)]
pub enum TxnOp {
  Put(TxnPutOp),
  Delete(TxnDeleteOp),
}

#[deriving(Clone)]
pub struct TxnPutOp {
  key: ~str,
  value: ~[u8],
}

impl<E, S: Encoder<E>> Encodable<S, E> for TxnPutOp {
  fn encode(&self, s: &mut S) -> Result<(), E> {
    match s.emit_str(self.key) {
      Ok(()) => (),
      Err(e) => return Err(e),
    }
    let value: &[u8] = self.value;
    match s.emit_str(value.to_base64(base64::STANDARD)) {
      Ok(()) => (),
      Err(e) => return Err(e),
    }
    Ok(())
  }
}

impl<E, D: Decoder<E>> Decodable<D, E> for TxnPutOp {
  fn decode(d: &mut D) -> Result<TxnPutOp, E> {
    // FIXME handle errors.
    let key = d.read_str().ok().unwrap();
    let value = d.read_str().ok().unwrap()
        .from_base64().ok().unwrap();
    let op = TxnPutOp{key: key, value: value};
    Ok(op)
  }
}

#[deriving(Clone)]
#[deriving(Decodable, Encodable)]
pub struct TxnDeleteOp {
  key: ~str,
}

#[deriving(Clone)]
#[deriving(Decodable, Encodable)]
pub struct Txn {
  xid: TxnId,
  ops: Vec<TxnOp>,
}

impl Txn {
  pub fn acceptable(&self) -> bool {
    true
  }
}

#[deriving(Clone)]
#[deriving(Decodable, Encodable)]
pub enum ProtocolMsg {
  Heartbeat,
  Timeout,
  // Discovery phase.
  CurrentEpoch(Epoch),
  NewEpoch(Epoch, TxnId),
  AckEpoch(Epoch, TxnId),
  ReqEpochHistory(Epoch, TxnId),
  AckEpochHistory(Epoch, Vec<Txn>),
  // Synchronization phase.
  NewMaster(Epoch, Vec<Txn>),
  AckMaster(Epoch),
  CommitMaster(Epoch),
  // Broadcast phase.
  Propose(Epoch, Txn),
  Ack(Epoch, TxnId),
  Commit(Epoch, TxnId),
}

enum ProtocolPhase {
  Discovery,
  Synchronization,
  Broadcast,
}

enum ProtocolState {
  Electing,
  Following,
  Leading,
}

pub struct SharedState {
  identity: HostId,
  history: Vec<Txn>,
}

impl SharedState {
  pub fn new() -> SharedState {
    SharedState{
      identity: HostId(0),
      history: Vec::new(),
    }
  }
}

pub struct MasterProcess {
  helper: ProcessHelper,
  config: Arc<AhabConfig>,
  phase: ProtocolPhase,
  quorum: HashSet<HostAddr>,
  epoch: Epoch,
  shared: Arc<RWLock<SharedState>>,
}

impl MasterProcess {
  pub fn new(config: Arc<AhabConfig>) -> MasterProcess {
    MasterProcess{
      helper: ProcessHelper::new(),
      config: config,
      phase: Discovery,
      quorum: HashSet::new(),
      epoch: 0,
      shared: Arc::new(RWLock::new(SharedState::new())),
    }
  }

  pub fn quorum_min_size(&self) -> uint {
    3
  }

  pub fn quorum_max_size(&self) -> uint {
    5
  }
}

impl Process<ProtocolMsg> for MasterProcess {
  fn send(&self, dest: &HostAddr, msg: ProtocolMsg) {
  }

  fn recv(&self) -> (HostAddr, ProtocolMsg) {
    self.helper.recv();
    (HostAddr::default(), Heartbeat)
  }

  fn process(&mut self) {
    let identity = HostAddr::default();
    match self.phase {
      Discovery => {
        // Receive from a quorum of followers CurrentEpoch(e).
        let mut quorum_epochs = HashMap::<HostAddr, Epoch>::new();
        loop {
          match self.recv() {
            (addr, msg) => match msg {
              CurrentEpoch(e) => {
                self.quorum.insert(addr);
                quorum_epochs.insert(addr, e);
                if self.quorum.len() == self.quorum_max_size() {
                  break;
                }
              },
              Timeout => {
                if self.quorum.len() >= self.quorum_min_size() {
                  break;
                }
              },
              _ => (),
            },
          }
        }

        // Send to quorum NewEpoch(e') s.t. e' = max(e received from quorum) + 1.
        self.epoch = {
          let mut sup_epoch: Epoch = 0;
          for (_, &e) in quorum_epochs.iter() {
            sup_epoch = max(sup_epoch, e);
          }
          sup_epoch + 1
        };
        assert!(self.epoch != 0);
        for (addr, _) in quorum_epochs.iter() {
          // FIXME read txn history from master process?
          self.send(addr, NewEpoch(self.epoch, TxnId::lower_bound()));
        }

        // Receive from quorum AckEpoch(m, diff).
        let mut quorum_xids = HashMap::<HostAddr, TxnId>::new();
        loop {
          match self.recv() {
            (addr, msg) => match msg {
              AckEpoch(e, xid) => {
                if self.quorum.contains(&addr) {
                  quorum_xids.insert(addr, xid);
                }
                if quorum_xids.len() == self.quorum_max_size() {
                  break;
                }
              },
              Timeout => {
                if quorum_xids.len() >= self.quorum_min_size() {
                  break;
                }
              },
              _ => (),
            }
          }
        }

        // Select a follower in quorum and its diff.
        let chosen_host = {
          let mut chosen_host = identity;
          let mut sup_xid = TxnId::lower_bound();
          for (&addr, &xid) in quorum_xids.iter() {
            if xid > sup_xid {
              chosen_host = addr;
              sup_xid = xid;
            }
          }
          chosen_host
        };

        // (Send to chosen follower ReqEpochHistory(e', xid').)
        let last_xid = {
          let shared = self.shared.read();
          match shared.history.last() {
            Some(txn) => txn.xid,
            None => TxnId::lower_bound(),
          }
        };
        self.send(&chosen_host, ReqEpochHistory(self.epoch, last_xid));

        // (Receive from chosen follower AckEpochHistory(e', diff).)
        let (e, diff) = match_until!(self.recv_from(&chosen_host), AckEpochHistory(e, diff) => (e, diff));
        assert!(e == self.epoch);
        // TODO adjust the dual follower history w/ the diff.

        // Transition to Synchronization phase.
        self.phase = Synchronization;
      },
      Synchronization => {
        // Send to quorum NewMaster(e', diff).
        // Receive from quorum AckMaster(e', diff), send to quorum
        // CommitMaster(e', diff), and transition to Broadcast phase.
      },
      Broadcast => {
        // Receive from primary process a proposed txn.
        // Send to quorum Propose(e', txn).
        // Receive from quorum Ack(e', txn).
        // Send to all followers Commit(e', txn).
      },
    }
  }
}

pub struct SlaveProcess {
  helper: ProcessHelper,
  config: Arc<AhabConfig>,
  phase: ProtocolPhase,
  last_epoch_prop: Epoch,
  last_master_prop: Epoch,
  accepted_txns: TreeMap<TxnId, Txn>,
  committing_txns: TreeMap<TxnId, Txn>,
  shared: Arc<RWLock<SharedState>>,
}

impl SlaveProcess {
  pub fn new(config: Arc<AhabConfig>) -> SlaveProcess {
    SlaveProcess{
      helper: ProcessHelper::new(),
      config: config,
      phase: Discovery,
      last_epoch_prop: 0,
      last_master_prop: 0,
      accepted_txns: TreeMap::new(),
      committing_txns: TreeMap::new(),
      //history: Vec::new(),
      shared: Arc::new(RWLock::new(SharedState::new())),
    }
  }

  pub fn infer_master(&self) -> HostId {
    HostId(0)
  }
}

impl Process<ProtocolMsg> for SlaveProcess {
  fn send(&self, dest: &HostAddr, msg: ProtocolMsg) {
  }

  fn recv(&self) -> (HostAddr, ProtocolMsg) {
    self.helper.recv();
    (HostAddr::default(), Heartbeat)
  }

  fn process(&mut self) {
    let identity = HostId(0);
    let leader = HostAddr::default();
    loop {
      match self.phase {
        Discovery => {
          // Send to leader CurrentEpoch(self.last_epoch_prop).
          self.send(&leader, CurrentEpoch(self.last_epoch_prop));
          // Receive from leader NewEpoch(e).
          let (e, last_xid) = match_until!(self.recv_from(&leader), NewEpoch(e, xid) => (e, xid));
          // If self.last_epoch_prop < e, then set self.last_epoch_prop = e, send to
          // leader AckEpoch(self.last_master_prop, diff), and transition to
          // Synchronization phase.
          if self.last_epoch_prop < e {
            self.last_epoch_prop = e;
            self.send(&leader, AckEpoch(self.last_master_prop, TxnId::lower_bound())); // FIXME
            self.phase = Synchronization;
          }
        },
        Synchronization => {
          // Receive from leader NewMaster(e, diff).
          // If self.last_epoch_prop != e, then transition to Discovery phase.
          let (e, diff) = match_until!(self.recv_from(&leader), NewMaster(e, diff) => (e, diff));
          if e != self.last_epoch_prop {
            self.phase = Discovery;
            continue;
          }

          // Atomically:
          // 1. set self.last_epoch_prop = e,
          // 2. for each txn in diff, accept txn.
          // (If failure, then transition to Discovery phase.)
          let accepted_txns = {
            let mut accepted_txns = Vec::<Txn>::new();
            let mut diff_accepted = true;
            for txn in diff.move_iter() {
              if txn.acceptable() {
                accepted_txns.push(txn);
              } else {
                diff_accepted = false;
                break;
              }
            }
            if diff_accepted {
              self.last_master_prop = e;
            } else {
              self.phase = Discovery;
              continue;
            }
            accepted_txns
          };

          // Send to leader AckMaster.
          self.send(&leader, AckMaster(self.last_epoch_prop));

          // Receive from leader CommitMaster.
          // (If self.last_epoch_prop != e, then transition to Discovery phase.)
          let e = match_until!(self.recv_from(&leader), CommitMaster(e) => e);
          if e != self.last_epoch_prop {
            self.phase = Discovery;
            continue;
          }

          // For each accepted txn, deliver txn.
          {
            let mut shared = self.shared.write();
            for txn in accepted_txns.move_iter() {
              shared.history.push(txn);
            }
          }

          // Transition to Broadcast phase.
          // If self.infer_master() is itself, invoke self.ready(e).
          self.phase = Broadcast;
          if identity == self.infer_master() {
            // FIXME
          }
        },
        Broadcast => {
          match self.recv_from(&leader) {
            Propose(e, txn) => {
              // Accept proposed txns from leader and append each txn to
              // self.history.
              self.accepted_txns.insert(txn.xid, txn);
            },
            Commit(e, xid) => {
              // Upon receiving from leader Commit(e, txn), and when all txn'
              // s.t. txn' < txn are committed, commit txn.
              match self.accepted_txns.pop(&xid) {
                Some(txn) => {
                  self.committing_txns.insert(xid, txn);
                },
                None => (),
              }
              let mut to_commit_xids = Vec::<TxnId>::new();
              'commit_all: for (&xid, txn) in self.committing_txns.iter() {
                for (&acc_xid, acc_txn) in self.accepted_txns.iter() {
                  if acc_xid < xid {
                    break 'commit_all;
                  } else {
                    break;
                  }
                }
                to_commit_xids.push(xid);
              }
              {
                let mut shared = self.shared.write();
                for xid in to_commit_xids.iter() {
                  let txn = self.committing_txns.pop(xid).unwrap();
                  shared.history.push(txn);
                }
              }
            },
            _ => (),
          }
        },
      }
    }
  }
}
<|endoftext|>


<commit_before>//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in (0..numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     std::thread::Thread::spawn(move||
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     });
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

use std::sync::atomic::{AtomicUint, Ordering, ATOMIC_UINT_INIT};
use std::cell::UnsafeCell;
use std::ops::{Drop, Deref, DerefMut};
use thread_local;

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicUint,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicUint,
    data: &'a mut T,
}

#[allow(unstable)]
unsafe impl<T> Sync for Spinlock<T> {}

/// A Spinlock which may be used statically.
///
/// ```
/// use spinlock::{StaticSpinlock, STATIC_SPINLOCK_INIT};
///
/// static SPLCK: StaticSpinlock = STATIC_SPINLOCK_INIT;
///
/// fn demo() {
///     let lock = SPLCK.lock();
///     // do something with lock
///     drop(lock);
/// }
/// ```
pub type StaticSpinlock = Spinlock<()>;

/// A initializer for StaticSpinlock, containing no data.
pub const STATIC_SPINLOCK_INIT: StaticSpinlock = Spinlock {
    lock: ATOMIC_UINT_INIT,
    data: UnsafeCell { value: () },
};

#[deprecated = "renamed to STATIC_SPINLOCK_INIT"]
pub const INIT_STATIC_SPINLOCK: StaticSpinlock = STATIC_SPINLOCK_INIT;

impl<T> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: ATOMIC_UINT_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    fn obtain_lock(&self)
    {
        let current_id = thread_local::data().borrow().current_thread.id.as_usize();
        while self.lock.compare_and_swap(0, current_id, Ordering::SeqCst) != 0
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }

    pub fn held_by_current_thread(&self) -> bool {
        let current_thread_id = thread_local::data().borrow().current_thread.id.as_usize();
        self.lock.load(Ordering::Relaxed) == current_thread_id
    }
}

impl<'a, T> Deref for SpinlockGuard<'a, T>
{
    type Target = T;
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T> DerefMut for SpinlockGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(0, Ordering::SeqCst);
    }
}<commit_msg>catch errors if thread local data is already mutably borrowed<commit_after>//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in (0..numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     std::thread::Thread::spawn(move||
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     });
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

use std::sync::atomic::{AtomicUint, Ordering, ATOMIC_UINT_INIT};
use std::cell::UnsafeCell;
use std::ops::{Drop, Deref, DerefMut};
use thread_local;

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicUint,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicUint,
    data: &'a mut T,
}

#[allow(unstable)]
unsafe impl<T> Sync for Spinlock<T> {}

/// A Spinlock which may be used statically.
///
/// ```
/// use spinlock::{StaticSpinlock, STATIC_SPINLOCK_INIT};
///
/// static SPLCK: StaticSpinlock = STATIC_SPINLOCK_INIT;
///
/// fn demo() {
///     let lock = SPLCK.lock();
///     // do something with lock
///     drop(lock);
/// }
/// ```
pub type StaticSpinlock = Spinlock<()>;

/// A initializer for StaticSpinlock, containing no data.
pub const STATIC_SPINLOCK_INIT: StaticSpinlock = Spinlock {
    lock: ATOMIC_UINT_INIT,
    data: UnsafeCell { value: () },
};

#[deprecated = "renamed to STATIC_SPINLOCK_INIT"]
pub const INIT_STATIC_SPINLOCK: StaticSpinlock = STATIC_SPINLOCK_INIT;

impl<T> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: ATOMIC_UINT_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    fn obtain_lock(&self)
    {
        let current_id = thread_local::data().try_borrow().expect("thread local data mutably \
            borrowed while obtaining lock").current_thread.id.as_usize();
        while self.lock.compare_and_swap(0, current_id, Ordering::SeqCst) != 0
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }

    pub fn held_by_current_thread(&self) -> bool {
        let current_thread_id = thread_local::data().try_borrow().expect("thread local data \
            mutably borrowed while spinlock::held_by_current_thread")
            .current_thread.id.as_usize();
        self.lock.load(Ordering::Relaxed) == current_thread_id
    }
}

impl<'a, T> Deref for SpinlockGuard<'a, T>
{
    type Target = T;
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T> DerefMut for SpinlockGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(0, Ordering::SeqCst);
    }
}<|endoftext|>


<commit_before>use {Distribution, Generator};

/// A Bernoulli distribution.
#[derive(Clone, Copy)]
pub struct Bernoulli {
    /// The probability of success.
    pub p: f64,
    /// The probability of failure.
    pub q: f64,

    pq: f64,
}

impl Bernoulli {
    /// Create a Bernoulli distribution with success probability `p`.
    ///
    /// It should hold that `p > 0` and `p < 1`.
    #[inline]
    pub fn new(p: f64) -> Bernoulli {
        should!(p > 0.0 && p < 1.0);
        Bernoulli { p: p, q: 1.0 - p, pq: p * (1.0 - p) }
    }

    /// Create a Bernoulli distribution with failure probability `q`.
    ///
    /// It should hold `q > 0` and `q < 1`. The constructor is preferable when
    /// `q` is very small.
    #[inline]
    pub fn new_failprob(q: f64) -> Bernoulli {
        should!(q > 0.0 && q < 1.0);
        Bernoulli { p: 1.0 - q, q: q, pq: (1.0 - q) * q }
    }
}

impl Distribution for Bernoulli {
    type Value = u8;

    #[inline] fn mean(&self) -> f64 { self.p }
    #[inline] fn var(&self) -> f64 { self.pq }
    #[inline] fn skewness(&self) -> f64 { (1.0 - 2.0 * self.p) / (self.pq).sqrt() }
    #[inline] fn kurtosis(&self) -> f64 { (1.0 - 6.0 * self.pq) / (self.pq) }

    #[inline]
    fn median(&self) -> f64 {
        use std::cmp::Ordering::*;
        match self.p.partial_cmp(&self.q) {
            Some(Less) => 0.0,
            Some(Equal) => 0.5,
            Some(Greater) => 1.0,
            None => unreachable!(),
        }
    }

    #[inline]
    fn modes(&self) -> Vec<Self::Value> {
        use std::cmp::Ordering::*;
        match self.p.partial_cmp(&self.q) {
            Some(Less) => vec![0],
            Some(Equal) => vec![0, 1],
            Some(Greater) => vec![1],
            None => unreachable!(),
        }
    }

    #[inline] fn entropy(&self) -> f64 { -self.q * self.q.ln() - self.p * self.p.ln() }
    #[inline] fn cdf(&self, x: Self::Value) -> f64 { if x == 0 { self.q } else { 1.0 } }

    #[inline]
    fn inv_cdf(&self, p: f64) -> Self::Value {
        should!(0.0 <= p && p <= 1.0);
        if p <= self.q { 0 } else { 1 }
    }

    #[inline]
    fn pdf(&self, x: Self::Value) -> f64 {
        if x == 0 { self.q } else if x == 1 { self.p } else { 0.0 }
    }

    #[inline(always)]
    fn sample<G: Generator>(&self, generator: &mut G) -> Self::Value {
        if generator.next::<f64>() < self.q { 0 } else { 1 }
    }
}

#[cfg(test)]
mod tests {
    use assert;

    use {Distribution, Sampler};
    use distributions::Bernoulli;

    macro_rules! new(
        (failure $q:expr) => (Bernoulli::new_failprob($q));
        ($p:expr) => (Bernoulli::new($p));
    );

    #[test]
    fn mean() {
        assert_eq!(new!(0.5).mean(), 0.5);
    }

    #[test]
    fn var() {
        assert_eq!(new!(0.25).var(), 0.1875);
    }

    #[test]
    fn sd() {
        assert_eq!(new!(0.5).sd(), 0.5);
    }

    #[test]
    fn skewness() {
        assert_eq!(new!(0.5).skewness(), 0.0);
    }

    #[test]
    fn kurtosis() {
        assert_eq!(new!(0.5).kurtosis(), -2.0);
    }

    #[test]
    fn median() {
        assert_eq!(new!(0.25).median(), 0.0);
        assert_eq!(new!(0.5).median(), 0.5);
        assert_eq!(new!(0.75).median(), 1.0);
    }

    #[test]
    fn modes() {
        assert_eq!(new!(0.25).modes(), vec![0]);
        assert_eq!(new!(0.5).modes(), vec![0, 1]);
        assert_eq!(new!(0.75).modes(), vec![1]);
    }

    #[test]
    fn entropy() {
        let bernoullies = vec![new!(0.25), new!(0.5), new!(0.75)];
        assert::close(&bernoullies.iter().map(|d| d.entropy()).collect::<Vec<_>>(),
                      &vec![0.5623351446188083, 0.6931471805599453, 0.5623351446188083], 1e-16);
    }

    #[test]
    fn pdf() {
        let bernoulli = new!(0.25);
        assert_eq!(&(0..3).map(|x| bernoulli.pdf(x)).collect::<Vec<_>>(), &[0.75, 0.25, 0.0]);
    }

    #[test]
    fn cdf() {
        let bernoulli = new!(0.25);
        assert_eq!(&(0..3).map(|x| bernoulli.cdf(x)).collect::<Vec<_>>(), &[0.75, 1.0, 1.0]);
    }

    #[test]
    fn inv_cdf() {
        let bernoulli = new!(0.25);
        let p = vec![0.0, 0.25, 0.5, 0.75, 0.75000000001, 1.0];
        let x = vec![0, 0, 0, 0, 1, 1];
        assert_eq!(&p.iter().map(|&p| bernoulli.inv_cdf(p)).collect::<Vec<_>>(), &x);
    }

    #[test]
    fn sample() {
        assert!(Sampler(&new!(0.25), &mut ::generator()).take(100).fold(0, |a, b| a + b) <= 100);
    }
}
<commit_msg>Fix a typo<commit_after>use {Distribution, Generator};

/// A Bernoulli distribution.
#[derive(Clone, Copy)]
pub struct Bernoulli {
    /// The probability of success.
    pub p: f64,
    /// The probability of failure.
    pub q: f64,

    pq: f64,
}

impl Bernoulli {
    /// Create a Bernoulli distribution with success probability `p`.
    ///
    /// It should hold that `p > 0` and `p < 1`.
    #[inline]
    pub fn new(p: f64) -> Bernoulli {
        should!(p > 0.0 && p < 1.0);
        Bernoulli { p: p, q: 1.0 - p, pq: p * (1.0 - p) }
    }

    /// Create a Bernoulli distribution with failure probability `q`.
    ///
    /// It should hold that `q > 0` and `q < 1`. The constructor is preferable
    /// when `q` is very small.
    #[inline]
    pub fn new_failprob(q: f64) -> Bernoulli {
        should!(q > 0.0 && q < 1.0);
        Bernoulli { p: 1.0 - q, q: q, pq: (1.0 - q) * q }
    }
}

impl Distribution for Bernoulli {
    type Value = u8;

    #[inline] fn mean(&self) -> f64 { self.p }
    #[inline] fn var(&self) -> f64 { self.pq }
    #[inline] fn skewness(&self) -> f64 { (1.0 - 2.0 * self.p) / (self.pq).sqrt() }
    #[inline] fn kurtosis(&self) -> f64 { (1.0 - 6.0 * self.pq) / (self.pq) }

    #[inline]
    fn median(&self) -> f64 {
        use std::cmp::Ordering::*;
        match self.p.partial_cmp(&self.q) {
            Some(Less) => 0.0,
            Some(Equal) => 0.5,
            Some(Greater) => 1.0,
            None => unreachable!(),
        }
    }

    #[inline]
    fn modes(&self) -> Vec<Self::Value> {
        use std::cmp::Ordering::*;
        match self.p.partial_cmp(&self.q) {
            Some(Less) => vec![0],
            Some(Equal) => vec![0, 1],
            Some(Greater) => vec![1],
            None => unreachable!(),
        }
    }

    #[inline] fn entropy(&self) -> f64 { -self.q * self.q.ln() - self.p * self.p.ln() }
    #[inline] fn cdf(&self, x: Self::Value) -> f64 { if x == 0 { self.q } else { 1.0 } }

    #[inline]
    fn inv_cdf(&self, p: f64) -> Self::Value {
        should!(0.0 <= p && p <= 1.0);
        if p <= self.q { 0 } else { 1 }
    }

    #[inline]
    fn pdf(&self, x: Self::Value) -> f64 {
        if x == 0 { self.q } else if x == 1 { self.p } else { 0.0 }
    }

    #[inline(always)]
    fn sample<G: Generator>(&self, generator: &mut G) -> Self::Value {
        if generator.next::<f64>() < self.q { 0 } else { 1 }
    }
}

#[cfg(test)]
mod tests {
    use assert;

    use {Distribution, Sampler};
    use distributions::Bernoulli;

    macro_rules! new(
        (failure $q:expr) => (Bernoulli::new_failprob($q));
        ($p:expr) => (Bernoulli::new($p));
    );

    #[test]
    fn mean() {
        assert_eq!(new!(0.5).mean(), 0.5);
    }

    #[test]
    fn var() {
        assert_eq!(new!(0.25).var(), 0.1875);
    }

    #[test]
    fn sd() {
        assert_eq!(new!(0.5).sd(), 0.5);
    }

    #[test]
    fn skewness() {
        assert_eq!(new!(0.5).skewness(), 0.0);
    }

    #[test]
    fn kurtosis() {
        assert_eq!(new!(0.5).kurtosis(), -2.0);
    }

    #[test]
    fn median() {
        assert_eq!(new!(0.25).median(), 0.0);
        assert_eq!(new!(0.5).median(), 0.5);
        assert_eq!(new!(0.75).median(), 1.0);
    }

    #[test]
    fn modes() {
        assert_eq!(new!(0.25).modes(), vec![0]);
        assert_eq!(new!(0.5).modes(), vec![0, 1]);
        assert_eq!(new!(0.75).modes(), vec![1]);
    }

    #[test]
    fn entropy() {
        let bernoullies = vec![new!(0.25), new!(0.5), new!(0.75)];
        assert::close(&bernoullies.iter().map(|d| d.entropy()).collect::<Vec<_>>(),
                      &vec![0.5623351446188083, 0.6931471805599453, 0.5623351446188083], 1e-16);
    }

    #[test]
    fn pdf() {
        let bernoulli = new!(0.25);
        assert_eq!(&(0..3).map(|x| bernoulli.pdf(x)).collect::<Vec<_>>(), &[0.75, 0.25, 0.0]);
    }

    #[test]
    fn cdf() {
        let bernoulli = new!(0.25);
        assert_eq!(&(0..3).map(|x| bernoulli.cdf(x)).collect::<Vec<_>>(), &[0.75, 1.0, 1.0]);
    }

    #[test]
    fn inv_cdf() {
        let bernoulli = new!(0.25);
        let p = vec![0.0, 0.25, 0.5, 0.75, 0.75000000001, 1.0];
        let x = vec![0, 0, 0, 0, 1, 1];
        assert_eq!(&p.iter().map(|&p| bernoulli.inv_cdf(p)).collect::<Vec<_>>(), &x);
    }

    #[test]
    fn sample() {
        assert!(Sampler(&new!(0.25), &mut ::generator()).take(100).fold(0, |a, b| a + b) <= 100);
    }
}
<|endoftext|>


<commit_before><commit_msg>put new PokemonSlot method in old impl<commit_after><|endoftext|>