<commit_before>// Copyright 2016 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.

//! Documentation generation for rustbuild.
//!
//! This module implements generation for all bits and pieces of documentation
//! for the Rust project. This notably includes suites like the rust book, the
//! nomicon, standalone documentation, etc.
//!
//! Everything here is basically just a shim around calling either `rustbook` or
//! `rustdoc`.

use std::fs::{self, File};
use std::io::prelude::*;
use std::io;
use std::path::Path;
use std::process::Command;

use {Build, Compiler, Mode};
use util::{cp_r, symlink_dir};
use build_helper::up_to_date;

/// Invoke `rustbook` as compiled in `stage` for `target` for the doc book
/// `name` into the `out` path.
///
/// This will not actually generate any documentation if the documentation has
/// already been generated.
pub fn rustbook(build: &Build, target: &str, name: &str) {
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));

    let out = out.join(name);
    let compiler = Compiler::new(0, &build.config.build);
    let src = build.src.join("src/doc").join(name);
    let index = out.join("index.html");
    let rustbook = build.tool(&compiler, "rustbook");
    if up_to_date(&src, &index) && up_to_date(&rustbook, &index) {
        return
    }
    println!("Rustbook ({}) - {}", target, name);
    let _ = fs::remove_dir_all(&out);
    build.run(build.tool_cmd(&compiler, "rustbook")
                   .arg("build")
                   .arg(&src)
                   .arg("-d")
                   .arg(out));
}

pub fn book(build: &Build, target: &str, name: &str) {
    rustbook(build, target, &format!("{}/first-edition", name));
    rustbook(build, target, &format!("{}/second-edition", name));
}

/// Generates all standalone documentation as compiled by the rustdoc in `stage`
/// for the `target` into `out`.
///
/// This will list all of `src/doc` looking for markdown files and appropriately
/// perform transformations like substituting `VERSION`, `SHORT_HASH`, and
/// `STAMP` alongw ith providing the various header/footer HTML we've cutomized.
///
/// In the end, this is just a glorified wrapper around rustdoc!
pub fn standalone(build: &Build, target: &str) {
    println!("Documenting standalone ({})", target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));

    let compiler = Compiler::new(0, &build.config.build);

    let favicon = build.src.join("src/doc/favicon.inc");
    let footer = build.src.join("src/doc/footer.inc");
    let full_toc = build.src.join("src/doc/full-toc.inc");
    t!(fs::copy(build.src.join("src/doc/rust.css"), out.join("rust.css")));

    let version_input = build.src.join("src/doc/version_info.html.template");
    let version_info = out.join("version_info.html");

    if !up_to_date(&version_input, &version_info) {
        let mut info = String::new();
        t!(t!(File::open(&version_input)).read_to_string(&mut info));
        let info = info.replace("VERSION", &build.rust_release())
                       .replace("SHORT_HASH", build.rust_info.sha_short().unwrap_or(""))
                       .replace("STAMP", build.rust_info.sha().unwrap_or(""));
        t!(t!(File::create(&version_info)).write_all(info.as_bytes()));
    }

    for file in t!(fs::read_dir(build.src.join("src/doc"))) {
        let file = t!(file);
        let path = file.path();
        let filename = path.file_name().unwrap().to_str().unwrap();
        if !filename.ends_with(".md") || filename == "README.md" {
            continue
        }

        let html = out.join(filename).with_extension("html");
        let rustdoc = build.rustdoc(&compiler);
        if up_to_date(&path, &html) &&
           up_to_date(&footer, &html) &&
           up_to_date(&favicon, &html) &&
           up_to_date(&full_toc, &html) &&
           up_to_date(&version_info, &html) &&
           up_to_date(&rustdoc, &html) {
            continue
        }

        let mut cmd = Command::new(&rustdoc);
        build.add_rustc_lib_path(&compiler, &mut cmd);
        cmd.arg("--html-after-content").arg(&footer)
           .arg("--html-before-content").arg(&version_info)
           .arg("--html-in-header").arg(&favicon)
           .arg("--markdown-playground-url")
           .arg("https://play.rust-lang.org/")
           .arg("-o").arg(&out)
           .arg(&path);

        if filename == "not_found.md" {
            cmd.arg("--markdown-no-toc")
               .arg("--markdown-css")
               .arg("https://doc.rust-lang.org/rust.css");
        } else {
            cmd.arg("--markdown-css").arg("rust.css");
        }
        build.run(&mut cmd);
    }
}

/// Compile all standard library documentation.
///
/// This will generate all documentation for the standard library and its
/// dependencies. This is largely just a wrapper around `cargo doc`.
pub fn std(build: &Build, stage: u32, target: &str) {
    println!("Documenting stage{} std ({})", stage, target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));
    let compiler = Compiler::new(stage, &build.config.build);
    let compiler = if build.force_use_stage1(&compiler, target) {
        Compiler::new(1, compiler.host)
    } else {
        compiler
    };
    let out_dir = build.stage_out(&compiler, Mode::Libstd)
                       .join(target).join("doc");
    let rustdoc = build.rustdoc(&compiler);

    // Here what we're doing is creating a *symlink* (directory junction on
    // Windows) to the final output location. This is not done as an
    // optimization but rather for correctness. We've got three trees of
    // documentation, one for std, one for test, and one for rustc. It's then
    // our job to merge them all together.
    //
    // Unfortunately rustbuild doesn't know nearly as well how to merge doc
    // trees as rustdoc does itself, so instead of actually having three
    // separate trees we just have rustdoc output to the same location across
    // all of them.
    //
    // This way rustdoc generates output directly into the output, and rustdoc
    // will also directly handle merging.
    let my_out = build.crate_doc_out(target);
    build.clear_if_dirty(&my_out, &rustdoc);
    t!(symlink_dir_force(&my_out, &out_dir));

    let mut cargo = build.cargo(&compiler, Mode::Libstd, target, "doc");
    cargo.arg("--manifest-path")
         .arg(build.src.join("src/libstd/Cargo.toml"))
         .arg("--features").arg(build.std_features());

    // We don't want to build docs for internal std dependencies unless
    // in compiler-docs mode. When not in that mode, we whitelist the crates
    // for which docs must be built.
    if !build.config.compiler_docs {
        cargo.arg("--no-deps");
        for krate in &["alloc", "collections", "core", "std", "std_unicode"] {
            cargo.arg("-p").arg(krate);
            // Create all crate output directories first to make sure rustdoc uses
            // relative links.
            // FIXME: Cargo should probably do this itself.
            t!(fs::create_dir_all(out_dir.join(krate)));
        }
    }

    build.run(&mut cargo);
    cp_r(&my_out, &out);
}

/// Compile all libtest documentation.
///
/// This will generate all documentation for libtest and its dependencies. This
/// is largely just a wrapper around `cargo doc`.
pub fn test(build: &Build, stage: u32, target: &str) {
    println!("Documenting stage{} test ({})", stage, target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));
    let compiler = Compiler::new(stage, &build.config.build);
    let compiler = if build.force_use_stage1(&compiler, target) {
        Compiler::new(1, compiler.host)
    } else {
        compiler
    };
    let out_dir = build.stage_out(&compiler, Mode::Libtest)
                       .join(target).join("doc");
    let rustdoc = build.rustdoc(&compiler);

    // See docs in std above for why we symlink
    let my_out = build.crate_doc_out(target);
    build.clear_if_dirty(&my_out, &rustdoc);
    t!(symlink_dir_force(&my_out, &out_dir));

    let mut cargo = build.cargo(&compiler, Mode::Libtest, target, "doc");
    cargo.arg("--manifest-path")
         .arg(build.src.join("src/libtest/Cargo.toml"));
    build.run(&mut cargo);
    cp_r(&my_out, &out);
}

/// Generate all compiler documentation.
///
/// This will generate all documentation for the compiler libraries and their
/// dependencies. This is largely just a wrapper around `cargo doc`.
pub fn rustc(build: &Build, stage: u32, target: &str) {
    println!("Documenting stage{} compiler ({})", stage, target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));
    let compiler = Compiler::new(stage, &build.config.build);
    let compiler = if build.force_use_stage1(&compiler, target) {
        Compiler::new(1, compiler.host)
    } else {
        compiler
    };
    let out_dir = build.stage_out(&compiler, Mode::Librustc)
                       .join(target).join("doc");
    let rustdoc = build.rustdoc(&compiler);

    // See docs in std above for why we symlink
    let my_out = build.crate_doc_out(target);
    build.clear_if_dirty(&my_out, &rustdoc);
    t!(symlink_dir_force(&my_out, &out_dir));

    let mut cargo = build.cargo(&compiler, Mode::Librustc, target, "doc");
    cargo.arg("--manifest-path")
         .arg(build.src.join("src/rustc/Cargo.toml"))
         .arg("--features").arg(build.rustc_features());

    if build.config.compiler_docs {
        // src/rustc/Cargo.toml contains bin crates called rustc and rustdoc
        // which would otherwise overwrite the docs for the real rustc and
        // rustdoc lib crates.
        cargo.arg("-p").arg("rustc_driver")
             .arg("-p").arg("rustdoc");
    } else {
        // Like with libstd above if compiler docs aren't enabled then we're not
        // documenting internal dependencies, so we have a whitelist.
        cargo.arg("--no-deps");
        for krate in &["proc_macro"] {
            cargo.arg("-p").arg(krate);
        }
    }

    build.run(&mut cargo);
    cp_r(&my_out, &out);
}

/// Generates the HTML rendered error-index by running the
/// `error_index_generator` tool.
pub fn error_index(build: &Build, target: &str) {
    println!("Documenting error index ({})", target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));
    let compiler = Compiler::new(0, &build.config.build);
    let mut index = build.tool_cmd(&compiler, "error_index_generator");
    index.arg("html");
    index.arg(out.join("error-index.html"));

    // FIXME: shouldn't have to pass this env var
    index.env("CFG_BUILD", &build.config.build);

    build.run(&mut index);
}

fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> {
    if let Ok(m) = fs::symlink_metadata(dst) {
        if m.file_type().is_dir() {
            try!(fs::remove_dir_all(dst));
        } else {
            // handle directory junctions on windows by falling back to
            // `remove_dir`.
            try!(fs::remove_file(dst).or_else(|_| {
                fs::remove_dir(dst)
            }));
        }
    }

    symlink_dir(src, dst)
}
<commit_msg>build book index<commit_after>// Copyright 2016 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.

//! Documentation generation for rustbuild.
//!
//! This module implements generation for all bits and pieces of documentation
//! for the Rust project. This notably includes suites like the rust book, the
//! nomicon, standalone documentation, etc.
//!
//! Everything here is basically just a shim around calling either `rustbook` or
//! `rustdoc`.

use std::fs::{self, File};
use std::io::prelude::*;
use std::io;
use std::path::Path;
use std::process::Command;

use {Build, Compiler, Mode};
use util::{cp_r, symlink_dir};
use build_helper::up_to_date;

/// Invoke `rustbook` as compiled in `stage` for `target` for the doc book
/// `name` into the `out` path.
///
/// This will not actually generate any documentation if the documentation has
/// already been generated.
pub fn rustbook(build: &Build, target: &str, name: &str) {
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));

    let out = out.join(name);
    let compiler = Compiler::new(0, &build.config.build);
    let src = build.src.join("src/doc").join(name);
    let index = out.join("index.html");
    let rustbook = build.tool(&compiler, "rustbook");
    if up_to_date(&src, &index) && up_to_date(&rustbook, &index) {
        return
    }
    println!("Rustbook ({}) - {}", target, name);
    let _ = fs::remove_dir_all(&out);
    build.run(build.tool_cmd(&compiler, "rustbook")
                   .arg("build")
                   .arg(&src)
                   .arg("-d")
                   .arg(out));
}

/// Build the book and associated stuff.
///
/// We need to build:
///
/// * Book (first edition)
/// * Book (second edition)
/// * Index page
/// * Redirect pages
pub fn book(build: &Build, target: &str, name: &str) {
    // build book first edition
    rustbook(build, target, &format!("{}/first-edition", name));

    // build book second edition
    rustbook(build, target, &format!("{}/second-edition", name));

    // build the index page
    let index = format!("{}/index.md", name);
    invoke_rustdoc(build, target, &index);
}

fn invoke_rustdoc(build: &Build, target: &str, markdown: &str) {
    let out = build.doc_out(target);

    let compiler = Compiler::new(0, &build.config.build);

    let path = build.src.join("src/doc").join(markdown);

    let rustdoc = build.rustdoc(&compiler);

    let favicon = build.src.join("src/doc/favicon.inc");
    let footer = build.src.join("src/doc/footer.inc");
    t!(fs::copy(build.src.join("src/doc/rust.css"), out.join("rust.css")));

    let version_info = out.join("version_info.html");

    let mut cmd = Command::new(&rustdoc);

    build.add_rustc_lib_path(&compiler, &mut cmd);

    let out = out.join("book");

    cmd.arg("--html-after-content").arg(&footer)
        .arg("--html-before-content").arg(&version_info)
        .arg("--html-in-header").arg(&favicon)
        .arg("--markdown-playground-url")
        .arg("https://play.rust-lang.org/")
        .arg("-o").arg(&out)
        .arg(&path)
        .arg("--markdown-css")
        .arg("rust.css");

    build.run(&mut cmd);
}

/// Generates all standalone documentation as compiled by the rustdoc in `stage`
/// for the `target` into `out`.
///
/// This will list all of `src/doc` looking for markdown files and appropriately
/// perform transformations like substituting `VERSION`, `SHORT_HASH`, and
/// `STAMP` alongw ith providing the various header/footer HTML we've cutomized.
///
/// In the end, this is just a glorified wrapper around rustdoc!
pub fn standalone(build: &Build, target: &str) {
    println!("Documenting standalone ({})", target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));

    let compiler = Compiler::new(0, &build.config.build);

    let favicon = build.src.join("src/doc/favicon.inc");
    let footer = build.src.join("src/doc/footer.inc");
    let full_toc = build.src.join("src/doc/full-toc.inc");
    t!(fs::copy(build.src.join("src/doc/rust.css"), out.join("rust.css")));

    let version_input = build.src.join("src/doc/version_info.html.template");
    let version_info = out.join("version_info.html");

    if !up_to_date(&version_input, &version_info) {
        let mut info = String::new();
        t!(t!(File::open(&version_input)).read_to_string(&mut info));
        let info = info.replace("VERSION", &build.rust_release())
                       .replace("SHORT_HASH", build.rust_info.sha_short().unwrap_or(""))
                       .replace("STAMP", build.rust_info.sha().unwrap_or(""));
        t!(t!(File::create(&version_info)).write_all(info.as_bytes()));
    }

    for file in t!(fs::read_dir(build.src.join("src/doc"))) {
        let file = t!(file);
        let path = file.path();
        let filename = path.file_name().unwrap().to_str().unwrap();
        if !filename.ends_with(".md") || filename == "README.md" {
            continue
        }

        let html = out.join(filename).with_extension("html");
        let rustdoc = build.rustdoc(&compiler);
        if up_to_date(&path, &html) &&
           up_to_date(&footer, &html) &&
           up_to_date(&favicon, &html) &&
           up_to_date(&full_toc, &html) &&
           up_to_date(&version_info, &html) &&
           up_to_date(&rustdoc, &html) {
            continue
        }

        let mut cmd = Command::new(&rustdoc);
        build.add_rustc_lib_path(&compiler, &mut cmd);
        cmd.arg("--html-after-content").arg(&footer)
           .arg("--html-before-content").arg(&version_info)
           .arg("--html-in-header").arg(&favicon)
           .arg("--markdown-playground-url")
           .arg("https://play.rust-lang.org/")
           .arg("-o").arg(&out)
           .arg(&path);

        if filename == "not_found.md" {
            cmd.arg("--markdown-no-toc")
               .arg("--markdown-css")
               .arg("https://doc.rust-lang.org/rust.css");
        } else {
            cmd.arg("--markdown-css").arg("rust.css");
        }
        build.run(&mut cmd);
    }
}

/// Compile all standard library documentation.
///
/// This will generate all documentation for the standard library and its
/// dependencies. This is largely just a wrapper around `cargo doc`.
pub fn std(build: &Build, stage: u32, target: &str) {
    println!("Documenting stage{} std ({})", stage, target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));
    let compiler = Compiler::new(stage, &build.config.build);
    let compiler = if build.force_use_stage1(&compiler, target) {
        Compiler::new(1, compiler.host)
    } else {
        compiler
    };
    let out_dir = build.stage_out(&compiler, Mode::Libstd)
                       .join(target).join("doc");
    let rustdoc = build.rustdoc(&compiler);

    // Here what we're doing is creating a *symlink* (directory junction on
    // Windows) to the final output location. This is not done as an
    // optimization but rather for correctness. We've got three trees of
    // documentation, one for std, one for test, and one for rustc. It's then
    // our job to merge them all together.
    //
    // Unfortunately rustbuild doesn't know nearly as well how to merge doc
    // trees as rustdoc does itself, so instead of actually having three
    // separate trees we just have rustdoc output to the same location across
    // all of them.
    //
    // This way rustdoc generates output directly into the output, and rustdoc
    // will also directly handle merging.
    let my_out = build.crate_doc_out(target);
    build.clear_if_dirty(&my_out, &rustdoc);
    t!(symlink_dir_force(&my_out, &out_dir));

    let mut cargo = build.cargo(&compiler, Mode::Libstd, target, "doc");
    cargo.arg("--manifest-path")
         .arg(build.src.join("src/libstd/Cargo.toml"))
         .arg("--features").arg(build.std_features());

    // We don't want to build docs for internal std dependencies unless
    // in compiler-docs mode. When not in that mode, we whitelist the crates
    // for which docs must be built.
    if !build.config.compiler_docs {
        cargo.arg("--no-deps");
        for krate in &["alloc", "collections", "core", "std", "std_unicode"] {
            cargo.arg("-p").arg(krate);
            // Create all crate output directories first to make sure rustdoc uses
            // relative links.
            // FIXME: Cargo should probably do this itself.
            t!(fs::create_dir_all(out_dir.join(krate)));
        }
    }

    build.run(&mut cargo);
    cp_r(&my_out, &out);
}

/// Compile all libtest documentation.
///
/// This will generate all documentation for libtest and its dependencies. This
/// is largely just a wrapper around `cargo doc`.
pub fn test(build: &Build, stage: u32, target: &str) {
    println!("Documenting stage{} test ({})", stage, target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));
    let compiler = Compiler::new(stage, &build.config.build);
    let compiler = if build.force_use_stage1(&compiler, target) {
        Compiler::new(1, compiler.host)
    } else {
        compiler
    };
    let out_dir = build.stage_out(&compiler, Mode::Libtest)
                       .join(target).join("doc");
    let rustdoc = build.rustdoc(&compiler);

    // See docs in std above for why we symlink
    let my_out = build.crate_doc_out(target);
    build.clear_if_dirty(&my_out, &rustdoc);
    t!(symlink_dir_force(&my_out, &out_dir));

    let mut cargo = build.cargo(&compiler, Mode::Libtest, target, "doc");
    cargo.arg("--manifest-path")
         .arg(build.src.join("src/libtest/Cargo.toml"));
    build.run(&mut cargo);
    cp_r(&my_out, &out);
}

/// Generate all compiler documentation.
///
/// This will generate all documentation for the compiler libraries and their
/// dependencies. This is largely just a wrapper around `cargo doc`.
pub fn rustc(build: &Build, stage: u32, target: &str) {
    println!("Documenting stage{} compiler ({})", stage, target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));
    let compiler = Compiler::new(stage, &build.config.build);
    let compiler = if build.force_use_stage1(&compiler, target) {
        Compiler::new(1, compiler.host)
    } else {
        compiler
    };
    let out_dir = build.stage_out(&compiler, Mode::Librustc)
                       .join(target).join("doc");
    let rustdoc = build.rustdoc(&compiler);

    // See docs in std above for why we symlink
    let my_out = build.crate_doc_out(target);
    build.clear_if_dirty(&my_out, &rustdoc);
    t!(symlink_dir_force(&my_out, &out_dir));

    let mut cargo = build.cargo(&compiler, Mode::Librustc, target, "doc");
    cargo.arg("--manifest-path")
         .arg(build.src.join("src/rustc/Cargo.toml"))
         .arg("--features").arg(build.rustc_features());

    if build.config.compiler_docs {
        // src/rustc/Cargo.toml contains bin crates called rustc and rustdoc
        // which would otherwise overwrite the docs for the real rustc and
        // rustdoc lib crates.
        cargo.arg("-p").arg("rustc_driver")
             .arg("-p").arg("rustdoc");
    } else {
        // Like with libstd above if compiler docs aren't enabled then we're not
        // documenting internal dependencies, so we have a whitelist.
        cargo.arg("--no-deps");
        for krate in &["proc_macro"] {
            cargo.arg("-p").arg(krate);
        }
    }

    build.run(&mut cargo);
    cp_r(&my_out, &out);
}

/// Generates the HTML rendered error-index by running the
/// `error_index_generator` tool.
pub fn error_index(build: &Build, target: &str) {
    println!("Documenting error index ({})", target);
    let out = build.doc_out(target);
    t!(fs::create_dir_all(&out));
    let compiler = Compiler::new(0, &build.config.build);
    let mut index = build.tool_cmd(&compiler, "error_index_generator");
    index.arg("html");
    index.arg(out.join("error-index.html"));

    // FIXME: shouldn't have to pass this env var
    index.env("CFG_BUILD", &build.config.build);

    build.run(&mut index);
}

fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> {
    if let Ok(m) = fs::symlink_metadata(dst) {
        if m.file_type().is_dir() {
            try!(fs::remove_dir_all(dst));
        } else {
            // handle directory junctions on windows by falling back to
            // `remove_dir`.
            try!(fs::remove_file(dst).or_else(|_| {
                fs::remove_dir(dst)
            }));
        }
    }

    symlink_dir(src, dst)
}
<|endoftext|>


<commit_before><commit_msg>Add blocks tests missing file<commit_after>use ast::rules;

use super::utils::{ interpret_rule };

#[test]
fn test_do_block() {
    let (_val, env) = interpret_rule("y = 3; do y = 5 end", rules::block);
    assert_eq!(env, r#"{"y": RefCell { value: Number(5.0) }}"#);
}<|endoftext|>


<commit_before><commit_msg>Add padding to the logging<commit_after><|endoftext|>


<commit_before><commit_msg>Fix spelling<commit_after><|endoftext|>


<commit_before><commit_msg>Started newtest example<commit_after>extern crate pancurses;

use pancurses::*;

fn main() {
    let window = initscr();

    start_color();
    use_default_colors();

    cbreak();
    noecho();

    window.clear();
    window.refresh();

    window.keypad(true);

    init_pair(1, 15, COLOR_BLACK);
    init_pair(2, COLOR_BLACK, COLOR_YELLOW);

    mousemask(ALL_MOUSE_EVENTS, std::ptr::null_mut());

    endwin();
}
<|endoftext|>


<commit_before>
import middle::trans;
import trans::decl_cdecl_fn;
import middle::trans_common::T_f32;
import middle::trans_common::T_f64;
import middle::trans_common::T_fn;
import middle::trans_common::T_bool;
import middle::trans_common::T_i1;
import middle::trans_common::T_i8;
import middle::trans_common::T_i32;
import middle::trans_common::T_int;
import middle::trans_common::T_ivec;
import middle::trans_common::T_nil;
import middle::trans_common::T_opaque_chan_ptr;
import middle::trans_common::T_opaque_ivec;
import middle::trans_common::T_opaque_port_ptr;
import middle::trans_common::T_opaque_vec_ptr;
import middle::trans_common::T_ptr;
import middle::trans_common::T_size_t;
import middle::trans_common::T_str;
import middle::trans_common::T_void;
import lib::llvm::type_names;
import lib::llvm::llvm::ModuleRef;
import lib::llvm::llvm::ValueRef;
import lib::llvm::llvm::TypeRef;

type upcalls =
    {grow_task: ValueRef,
     _yield: ValueRef,
     sleep: ValueRef,
     _fail: ValueRef,
     kill: ValueRef,
     exit: ValueRef,
     malloc: ValueRef,
     free: ValueRef,
     shared_malloc: ValueRef,
     shared_free: ValueRef,
     mark: ValueRef,
     new_str: ValueRef,
     new_vec: ValueRef,
     vec_append: ValueRef,
     get_type_desc: ValueRef,
     ivec_resize: ValueRef,
     ivec_spill: ValueRef,
     ivec_resize_shared: ValueRef,
     ivec_spill_shared: ValueRef,
     cmp_type: ValueRef,
     log_type: ValueRef};

fn declare_upcalls(tn: type_names, tydesc_type: TypeRef,
                   taskptr_type: TypeRef, llmod: ModuleRef) -> @upcalls {
    fn decl(tn: type_names, llmod: ModuleRef, name: str, tys: [TypeRef],
          rv: TypeRef) -> ValueRef {
        let arg_tys: [TypeRef] = ~[];
        for t: TypeRef in tys { arg_tys += ~[t]; }
        let fn_ty = T_fn(arg_tys, rv);
        ret trans::decl_cdecl_fn(llmod, "upcall_" + name, fn_ty);
    }
    fn decl_with_taskptr(taskptr_type: TypeRef, tn: type_names,
                         llmod: ModuleRef, name: str, tys: [TypeRef],
                         rv: TypeRef) -> ValueRef {
        ret decl(tn, llmod, name, ~[taskptr_type] + tys, rv);
    }
    let dv = bind decl_with_taskptr(taskptr_type, tn, llmod, _, _, T_void());
    let d = bind decl_with_taskptr(taskptr_type, tn, llmod, _, _, _);
    let dr = bind decl(tn, llmod, _, _, _);

    let empty_vec: [TypeRef] = ~[];
    ret @{grow_task: dv("grow_task", ~[T_size_t()]),
          _yield: dv("yield", empty_vec),
          sleep: dv("sleep", ~[T_size_t()]),
          _fail: dv("fail", ~[T_ptr(T_i8()), T_ptr(T_i8()), T_size_t()]),
          kill: dv("kill", ~[taskptr_type]),
          exit: dv("exit", empty_vec),
          malloc:
              d("malloc", ~[T_size_t(), T_ptr(tydesc_type)], T_ptr(T_i8())),
          free: dv("free", ~[T_ptr(T_i8()), T_int()]),
          shared_malloc:
              d("shared_malloc", ~[T_size_t(), T_ptr(tydesc_type)],
                T_ptr(T_i8())),
          shared_free: dv("shared_free", ~[T_ptr(T_i8())]),
          mark: d("mark", ~[T_ptr(T_i8())], T_int()),
          new_str: d("new_str", ~[T_ptr(T_i8()), T_size_t()], T_ptr(T_str())),
          new_vec:
              d("new_vec", ~[T_size_t(), T_ptr(tydesc_type)],
                T_opaque_vec_ptr()),
          vec_append:
              d("vec_append",
                ~[T_ptr(tydesc_type), T_ptr(tydesc_type),
                  T_ptr(T_opaque_vec_ptr()), T_opaque_vec_ptr(), T_bool()],
                T_void()),
          get_type_desc:
              d("get_type_desc",
                ~[T_ptr(T_nil()), T_size_t(), T_size_t(), T_size_t(),
                  T_ptr(T_ptr(tydesc_type))], T_ptr(tydesc_type)),
          ivec_resize:
              d("ivec_resize", ~[T_ptr(T_opaque_ivec()), T_int()], T_void()),
          ivec_spill:
              d("ivec_spill", ~[T_ptr(T_opaque_ivec()), T_int()], T_void()),
          ivec_resize_shared:
              d("ivec_resize_shared", ~[T_ptr(T_opaque_ivec()), T_int()],
                T_void()),
          ivec_spill_shared:
              d("ivec_spill_shared", ~[T_ptr(T_opaque_ivec()), T_int()],
                T_void()),
          cmp_type:
              dr("cmp_type", ~[T_ptr(T_i1()), taskptr_type,
                 T_ptr(tydesc_type), T_ptr(T_ptr(tydesc_type)),
                 T_ptr(T_i8()), T_ptr(T_i8()), T_i8()],
                 T_void()),
          log_type:
              dr("log_type", ~[taskptr_type, T_ptr(tydesc_type),
                 T_ptr(T_i8()), T_i32()],
                 T_void())};
}
//
// 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>rustc: Add the dynastack upcalls to upcall.rs<commit_after>
import middle::trans;
import trans::decl_cdecl_fn;
import middle::trans_common::T_f32;
import middle::trans_common::T_f64;
import middle::trans_common::T_fn;
import middle::trans_common::T_bool;
import middle::trans_common::T_i1;
import middle::trans_common::T_i8;
import middle::trans_common::T_i32;
import middle::trans_common::T_int;
import middle::trans_common::T_ivec;
import middle::trans_common::T_nil;
import middle::trans_common::T_opaque_chan_ptr;
import middle::trans_common::T_opaque_ivec;
import middle::trans_common::T_opaque_port_ptr;
import middle::trans_common::T_opaque_vec_ptr;
import middle::trans_common::T_ptr;
import middle::trans_common::T_size_t;
import middle::trans_common::T_str;
import middle::trans_common::T_void;
import lib::llvm::type_names;
import lib::llvm::llvm::ModuleRef;
import lib::llvm::llvm::ValueRef;
import lib::llvm::llvm::TypeRef;

type upcalls =
    {grow_task: ValueRef,
     _yield: ValueRef,
     sleep: ValueRef,
     _fail: ValueRef,
     kill: ValueRef,
     exit: ValueRef,
     malloc: ValueRef,
     free: ValueRef,
     shared_malloc: ValueRef,
     shared_free: ValueRef,
     mark: ValueRef,
     new_str: ValueRef,
     new_vec: ValueRef,
     vec_append: ValueRef,
     get_type_desc: ValueRef,
     ivec_resize: ValueRef,
     ivec_spill: ValueRef,
     ivec_resize_shared: ValueRef,
     ivec_spill_shared: ValueRef,
     cmp_type: ValueRef,
     log_type: ValueRef,
     dynastack_mark: ValueRef,
     dynastack_alloc: ValueRef,
     dynastack_free: ValueRef};

fn declare_upcalls(tn: type_names, tydesc_type: TypeRef,
                   taskptr_type: TypeRef, llmod: ModuleRef) -> @upcalls {
    fn decl(tn: type_names, llmod: ModuleRef, name: str, tys: [TypeRef],
          rv: TypeRef) -> ValueRef {
        let arg_tys: [TypeRef] = ~[];
        for t: TypeRef in tys { arg_tys += ~[t]; }
        let fn_ty = T_fn(arg_tys, rv);
        ret trans::decl_cdecl_fn(llmod, "upcall_" + name, fn_ty);
    }
    fn decl_with_taskptr(taskptr_type: TypeRef, tn: type_names,
                         llmod: ModuleRef, name: str, tys: [TypeRef],
                         rv: TypeRef) -> ValueRef {
        ret decl(tn, llmod, name, ~[taskptr_type] + tys, rv);
    }
    let dv = bind decl_with_taskptr(taskptr_type, tn, llmod, _, _, T_void());
    let d = bind decl_with_taskptr(taskptr_type, tn, llmod, _, _, _);
    let dr = bind decl(tn, llmod, _, _, _);

    let empty_vec: [TypeRef] = ~[];
    ret @{grow_task: dv("grow_task", ~[T_size_t()]),
          _yield: dv("yield", empty_vec),
          sleep: dv("sleep", ~[T_size_t()]),
          _fail: dv("fail", ~[T_ptr(T_i8()), T_ptr(T_i8()), T_size_t()]),
          kill: dv("kill", ~[taskptr_type]),
          exit: dv("exit", empty_vec),
          malloc:
              d("malloc", ~[T_size_t(), T_ptr(tydesc_type)], T_ptr(T_i8())),
          free: dv("free", ~[T_ptr(T_i8()), T_int()]),
          shared_malloc:
              d("shared_malloc", ~[T_size_t(), T_ptr(tydesc_type)],
                T_ptr(T_i8())),
          shared_free: dv("shared_free", ~[T_ptr(T_i8())]),
          mark: d("mark", ~[T_ptr(T_i8())], T_int()),
          new_str: d("new_str", ~[T_ptr(T_i8()), T_size_t()], T_ptr(T_str())),
          new_vec:
              d("new_vec", ~[T_size_t(), T_ptr(tydesc_type)],
                T_opaque_vec_ptr()),
          vec_append:
              d("vec_append",
                ~[T_ptr(tydesc_type), T_ptr(tydesc_type),
                  T_ptr(T_opaque_vec_ptr()), T_opaque_vec_ptr(), T_bool()],
                T_void()),
          get_type_desc:
              d("get_type_desc",
                ~[T_ptr(T_nil()), T_size_t(), T_size_t(), T_size_t(),
                  T_ptr(T_ptr(tydesc_type))], T_ptr(tydesc_type)),
          ivec_resize:
              d("ivec_resize", ~[T_ptr(T_opaque_ivec()), T_int()], T_void()),
          ivec_spill:
              d("ivec_spill", ~[T_ptr(T_opaque_ivec()), T_int()], T_void()),
          ivec_resize_shared:
              d("ivec_resize_shared", ~[T_ptr(T_opaque_ivec()), T_int()],
                T_void()),
          ivec_spill_shared:
              d("ivec_spill_shared", ~[T_ptr(T_opaque_ivec()), T_int()],
                T_void()),
          cmp_type:
              dr("cmp_type", ~[T_ptr(T_i1()), taskptr_type,
                 T_ptr(tydesc_type), T_ptr(T_ptr(tydesc_type)),
                 T_ptr(T_i8()), T_ptr(T_i8()), T_i8()],
                 T_void()),
          log_type:
              dr("log_type", ~[taskptr_type, T_ptr(tydesc_type),
                 T_ptr(T_i8()), T_i32()],
                 T_void()),
          dynastack_mark:
              d("dynastack_mark", ~[], T_ptr(T_i8())),
          dynastack_alloc:
              d("dynastack_alloc", ~[T_size_t()], T_ptr(T_i8())),
          dynastack_free:
              d("dynastack_free", ~[T_ptr(T_i8())], T_void())};
}
//
// 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><commit_msg>Some work on the fibonacci problem, using Rust<commit_after>fn main() {
	let mut first = 1;
	let mut second = 1;
	let mut next = 0;

	for x in range (1, 100) {
		next = first;
		first = first + second;
		second = next;
		println!("{} ", first);
	}
}<|endoftext|>


<commit_before><commit_msg>tcp echo server not working<commit_after>/*
 * A simple echo server in TCP: accepts connections, read and write lines
 * Useful links:
 *   -https://github.com/mozilla/rust/blob/incoming/src/libstd/flatpipes.rs#L772
 *   -https://github.com/mozilla/rust/issues/4296
 *   -https://gist.github.com/thomaslee/4753338
 */

/*
 * TODO: does not work yet: the server blocks after "server is now listening".
 * When a client (e.g., telnet) connects, the message "New client" is not displayed
 */

extern mod std;
use std::net::tcp;
use std::net::ip;
use std::uv;
use core::pipes;

fn new_connect_cb(new_client: tcp::TcpNewConnection, _comm_chan: core::oldcomm::Chan<core::option::Option<std::net_tcp::TcpErrData>>) {
   do task::spawn {
      error!("New client");
      error!("going to accept");
      let result = tcp::accept(new_client);
      error!("ok for the call");
      if result.is_ok(){
         error!("Accepted!");
         let socket = result::unwrap(move result);
         error!("Unwrapped");
         // Now do stuff with this socket
         let data = socket.read(1); // XXX: This blocks
         io::println(fmt!("%?", data));
      }else{
         error!("Not accepted!");
      }
   }
}

fn main() {
   // We need to create several tasks
   // 1 to listen, 1 to accept
   // We need a channel between the tasks

   do task::spawn_sched(task::ManualThreads(1)) {
      let result = tcp::listen(ip::v4::parse_addr("127.0.0.1"), 4000, 100,
            uv::global_loop::get(),
            |_comm_chan|{
            io::println("Server is now listening!");
            },
            new_connect_cb
      );

      if result.is_err() {
         fail fmt!("failed listen: %?", result.get_err());
      }
   }
}
<|endoftext|>


<commit_before><commit_msg>'prime-factors': refactor<commit_after><|endoftext|>


<commit_before><commit_msg>Macro and iface tricks to simulate self move.<commit_after>/*
The first test case using pipes. The idea is to break this into
several stages for prototyping. Here's the plan:

1. Write an already-compiled protocol using existing ports and chans.

2. Take the already-compiled version and add the low-level
synchronization code instead.

3. Write a syntax extension to compile the protocols.

At some point, we'll need to add support for select.

This file does horrible things to pretend we have self-move.

*/

// Hopefully someday we'll move this into core.
mod pipes {
    import unsafe::{forget, reinterpret_cast};

    enum state {
        empty,
        full,
        blocked,
        terminated
    }

    type packet<T: send> = {
        mut state: state,
        mut blocked_task: option<task::task>,
        mut payload: option<T>
    };

    fn packet<T: send>() -> *packet<T> unsafe {
        let p: *packet<T> = unsafe::transmute(~{
            mut state: empty,
            mut blocked_task: none::<task::task>,
            mut payload: none::<T>
        });
        p
    }

    #[abi = "rust-intrinsic"]
    native mod rusti {
        fn atomic_xchng(&dst: int, src: int) -> int;
        fn atomic_xchng_acq(&dst: int, src: int) -> int;
        fn atomic_xchng_rel(&dst: int, src: int) -> int;
    }

    // We should consider moving this to core::unsafe, although I
    // suspect graydon would want us to use void pointers instead.
    unsafe fn uniquify<T>(x: *T) -> ~T {
        unsafe { unsafe::reinterpret_cast(x) }
    }

    fn swap_state_acq(&dst: state, src: state) -> state {
        unsafe {
            reinterpret_cast(rusti::atomic_xchng_acq(
                *(ptr::mut_addr_of(dst) as *mut int),
                src as int))
        }
    }

    fn swap_state_rel(&dst: state, src: state) -> state {
        unsafe {
            reinterpret_cast(rusti::atomic_xchng_rel(
                *(ptr::mut_addr_of(dst) as *mut int),
                src as int))
        }
    }

    fn send<T: send>(-p: send_packet<T>, -payload: T) {
        let p = p.unwrap();
        let p = unsafe { uniquify(p) };
        assert (*p).payload == none;
        (*p).payload <- some(payload);
        let old_state = swap_state_rel((*p).state, full);
        alt old_state {
          empty {
            // Yay, fastpath.

            // The receiver will eventually clean this up.
            unsafe { forget(p); }
          }
          full { fail "duplicate send" }
          blocked {
            // FIXME: once the target will actually block, tell the
            // scheduler to wake it up.

            // The receiver will eventually clean this up.
            unsafe { forget(p); }
          }
          terminated {
            // The receiver will never receive this. Rely on drop_glue
            // to clean everything up.
          }
        }
    }

    fn recv<T: send>(-p: recv_packet<T>) -> option<T> {
        let p = p.unwrap();
        let p = unsafe { uniquify(p) };
        loop {
            let old_state = swap_state_acq((*p).state,
                                           blocked);
            alt old_state {
              empty | blocked { task::yield(); }
              full {
                let mut payload = none;
                payload <-> (*p).payload;
                ret some(option::unwrap(payload))
              }
              terminated {
                assert old_state == terminated;
                ret none;
              }
            }
        }
    }

    fn sender_terminate<T: send>(p: *packet<T>) {
        let p = unsafe { uniquify(p) };
        alt swap_state_rel((*p).state, terminated) {
          empty | blocked {
            // The receiver will eventually clean up.
            unsafe { forget(p) }
          }
          full {
            // This is impossible
            fail "you dun goofed"
          }
          terminated {
            // I have to clean up, use drop_glue
          }
        }
    }

    fn receiver_terminate<T: send>(p: *packet<T>) {
        let p = unsafe { uniquify(p) };
        alt swap_state_rel((*p).state, terminated) {
          empty {
            // the sender will clean up
            unsafe { forget(p) }
          }
          blocked {
            // this shouldn't happen.
            fail "terminating a blocked packet"
          }
          terminated | full {
            // I have to clean up, use drop_glue
          }
        }
    }

    class send_packet<T: send> {
        let mut p: option<*packet<T>>;
        new(p: *packet<T>) { self.p = some(p); }
        drop {
            if self.p != none {
                let mut p = none;
                p <-> self.p;
                sender_terminate(option::unwrap(p))
            }
        }
        fn unwrap() -> *packet<T> {
            let mut p = none;
            p <-> self.p;
            option::unwrap(p)
        }
    }

    class recv_packet<T: send> {
        let mut p: option<*packet<T>>;
        new(p: *packet<T>) { self.p = some(p); }
        drop {
            if self.p != none {
                let mut p = none;
                p <-> self.p;
                receiver_terminate(option::unwrap(p))
            }
        }
        fn unwrap() -> *packet<T> {
            let mut p = none;
            p <-> self.p;
            option::unwrap(p)
        }
    }

    fn entangle<T: send>() -> (send_packet<T>, recv_packet<T>) {
        let p = packet();
        (send_packet(p), recv_packet(p))
    }
}

mod pingpong {
    enum ping { ping, }
    enum ping_message = *pipes::packet<pong_message>;
    enum pong { pong, }
    enum pong_message = *pipes::packet<ping_message>;

    fn init() -> (client::ping, server::ping) {
        pipes::entangle()
    }

    mod client {
        type ping = pipes::send_packet<pingpong::ping_message>;
        type pong = pipes::recv_packet<pingpong::pong_message>;
    }

    impl abominable for client::ping {
        fn send() -> fn@(-client::ping, ping) -> client::pong {
            {|pipe, data|
                let p = pipes::packet();
                pipes::send(pipe, pingpong::ping_message(p));
                pipes::recv_packet(p)
            }
        }
    }

    impl abominable for client::pong {
        fn recv() -> fn@(-client::pong) -> (client::ping, pong) {
            {|pipe|
                let packet = pipes::recv(pipe);
                if packet == none {
                    fail "sender closed the connection"
                }
                let p : pong_message = option::unwrap(packet);
                (pipes::send_packet(*p), pong)
            }
        }
    }

    mod server {
        type ping = pipes::recv_packet<pingpong::ping_message>;
        type pong = pipes::send_packet<pingpong::pong_message>;
    }

    impl abominable for server::ping {
        fn recv() -> fn@(-server::ping) -> (server::pong, ping) {
            {|pipe|
                let packet = pipes::recv(pipe);
                if packet == none {
                    fail "sender closed the connection"
                }
                let p : ping_message = option::unwrap(packet);
                (pipes::send_packet(*p), ping)
            }
        }
    }

    impl abominable for server::pong {
        fn send() -> fn@(-server::pong, pong) -> server::ping {
            {|pipe, data|
                let p = pipes::packet();
                pipes::send(pipe, pingpong::pong_message(p));
                pipes::recv_packet(p)
            }
        }
    }
}

mod test {
    import pingpong::{ping, pong, abominable};

    fn macros() {
        #macro[
            [#send[chan, data, ...],
             chan.send()(chan, data, ...)]
        ];
        #macro[
            [#recv[chan],
             chan.recv()(chan)]
        ];
    }

    fn client(-chan: pingpong::client::ping) {
        let chan = #send(chan, ping);
        log(error, "Sent ping");
        let (chan, _data) = #recv(chan);
        log(error, "Received pong");
    }

    fn server(-chan: pingpong::server::ping) {
        let (chan, _data) = #recv(chan);
        log(error, "Received ping");
        let chan = #send(chan, pong);
        log(error, "Sent pong");
    }
}

fn main() {
    let (client_, server_) = pingpong::init();
    let client_ = ~mut some(client_);
    let server_ = ~mut some(server_);

    task::spawn {|move client_|
        let mut client__ = none;
        *client_ <-> client__;
        test::client(option::unwrap(client__));
    };
    task::spawn {|move server_|
        let mut server_ˊ = none;
        *server_ <-> server_ˊ;
        test::server(option::unwrap(server_ˊ));
    };
}
<|endoftext|>


<commit_before>/*!

Sendable hash maps.  Very much a work in progress.

*/

/**
 * A function that returns a hash of a value
 *
 * The hash should concentrate entropy in the lower bits.
 */
type HashFn<K> = pure fn~(K) -> uint;
type EqFn<K> = pure fn~(K, K) -> bool;

/// Open addressing with linear probing.
mod linear {
    export LinearMap, linear_map, linear_map_with_capacity, public_methods;

    const initial_capacity: uint = 32u; // 2^5
    type Bucket<K,V> = {hash: uint, key: K, value: V};
    enum LinearMap<K,V> {
        LinearMap_({
            hashfn: pure fn~(x: &K) -> uint,
            eqfn: pure fn~(x: &K, y: &K) -> bool,
            resize_at: uint,
            size: uint,
            buckets: ~[option<Bucket<K,V>>]})
    }

    // FIXME(#2979) -- with #2979 we could rewrite found_entry
    // to have type option<&bucket<K,V>> which would be nifty
    enum SearchResult {
        FoundEntry(uint), FoundHole(uint), TableFull
    }

    fn resize_at(capacity: uint) -> uint {
        ((capacity as float) * 3. / 4.) as uint
    }

    fn linear_map<K,V>(
        +hashfn: pure fn~(x: &K) -> uint,
        +eqfn: pure fn~(x: &K, y: &K) -> bool) -> LinearMap<K,V> {

        linear_map_with_capacity(hashfn, eqfn, 32)
    }

    fn linear_map_with_capacity<K,V>(
        +hashfn: pure fn~(x: &K) -> uint,
        +eqfn: pure fn~(x: &K, y: &K) -> bool,
        initial_capacity: uint) -> LinearMap<K,V> {

        LinearMap_({
            hashfn: hashfn,
            eqfn: eqfn,
            resize_at: resize_at(initial_capacity),
            size: 0,
            buckets: vec::from_fn(initial_capacity, |_i| none)})
    }

    priv impl<K, V> &const LinearMap<K,V> {
        #[inline(always)]
        pure fn to_bucket(h: uint) -> uint {
            // FIXME(#3041) borrow a more sophisticated technique here from
            // Gecko, for example borrowing from Knuth, as Eich so
            // colorfully argues for here:
            // https://bugzilla.mozilla.org/show_bug.cgi?id=743107#c22
            h % self.buckets.len()
        }

        #[inline(always)]
        pure fn next_bucket(idx: uint, len_buckets: uint) -> uint {
            let n = (idx + 1) % len_buckets;
            unsafe{ // argh. log not considered pure.
                debug!{"next_bucket(%?, %?) = %?", idx, len_buckets, n};
            }
            return n;
        }

        #[inline(always)]
        pure fn bucket_sequence(hash: uint, op: fn(uint) -> bool) -> uint {
            let start_idx = self.to_bucket(hash);
            let len_buckets = self.buckets.len();
            let mut idx = start_idx;
            loop {
                if !op(idx) {
                    return idx;
                }
                idx = self.next_bucket(idx, len_buckets);
                if idx == start_idx {
                    return start_idx;
                }
            }
        }

        #[inline(always)]
        pure fn bucket_for_key(
            buckets: &[option<Bucket<K,V>>],
            k: &K) -> SearchResult {

            let hash = self.hashfn(k);
            self.bucket_for_key_with_hash(buckets, hash, k)
        }

        #[inline(always)]
        pure fn bucket_for_key_with_hash(
            buckets: &[option<Bucket<K,V>>],
            hash: uint,
            k: &K) -> SearchResult {

            let _ = for self.bucket_sequence(hash) |i| {
                match buckets[i] {
                  some(bkt) => if bkt.hash == hash && self.eqfn(k, &bkt.key) {
                    return FoundEntry(i);
                  },
                  none => return FoundHole(i)
                }
            };
            return TableFull;
        }
    }

    priv impl<K,V> &mut LinearMap<K,V> {
        /// Expands the capacity of the array and re-inserts each
        /// of the existing buckets.
        fn expand() {
            let old_capacity = self.buckets.len();
            let new_capacity = old_capacity * 2;
            self.resize_at = ((new_capacity as float) * 3.0 / 4.0) as uint;

            let mut old_buckets = vec::from_fn(new_capacity, |_i| none);
            self.buckets <-> old_buckets;

            for uint::range(0, old_capacity) |i| {
                let mut bucket = none;
                bucket <-> old_buckets[i];
                if bucket.is_some() {
                    self.insert_bucket(bucket);
                }
            }
        }

        fn insert_bucket(+bucket: option<Bucket<K,V>>) {
            let {hash, key, value} <- option::unwrap(bucket);
            let _ = self.insert_internal(hash, key, value);
        }

        /// Inserts the key value pair into the buckets.
        /// Assumes that there will be a bucket.
        /// True if there was no previous entry with that key
        fn insert_internal(hash: uint, +k: K, +v: V) -> bool {
            match self.bucket_for_key_with_hash(self.buckets, hash, &k) {
              TableFull => {fail ~"Internal logic error";}
              FoundHole(idx) => {
                debug!{"insert fresh (%?->%?) at idx %?, hash %?",
                       k, v, idx, hash};
                self.buckets[idx] = some({hash: hash, key: k, value: v});
                self.size += 1;
                return true;
              }
              FoundEntry(idx) => {
                debug!{"insert overwrite (%?->%?) at idx %?, hash %?",
                       k, v, idx, hash};
                self.buckets[idx] = some({hash: hash, key: k, value: v});
                return false;
              }
            }
        }
    }

    impl<K,V> &mut LinearMap<K,V> {
        fn insert(+k: K, +v: V) -> bool {
            if self.size >= self.resize_at {
                // n.b.: We could also do this after searching, so
                // that we do not resize if this call to insert is
                // simply going to update a key in place.  My sense
                // though is that it's worse to have to search through
                // buckets to find the right spot twice than to just
                // resize in this corner case.
                self.expand();
            }

            let hash = self.hashfn(&k);
            self.insert_internal(hash, k, v)
        }

        fn remove(k: &K) -> bool {
            // Removing from an open-addressed hashtable
            // is, well, painful.  The problem is that
            // the entry may lie on the probe path for other
            // entries, so removing it would make you think that
            // those probe paths are empty.
            //
            // To address this we basically have to keep walking,
            // re-inserting entries we find until we reach an empty
            // bucket.  We know we will eventually reach one because
            // we insert one ourselves at the beginning (the removed
            // entry).
            //
            // I found this explanation elucidating:
            // http://www.maths.lse.ac.uk/Courses/MA407/del-hash.pdf

            let mut idx = match self.bucket_for_key(self.buckets, k) {
              TableFull | FoundHole(_) => {
                return false;
              }
              FoundEntry(idx) => {
                idx
              }
            };

            let len_buckets = self.buckets.len();
            self.buckets[idx] = none;
            idx = self.next_bucket(idx, len_buckets);
            while self.buckets[idx].is_some() {
                let mut bucket = none;
                bucket <-> self.buckets[idx];
                self.insert_bucket(bucket);
                idx = self.next_bucket(idx, len_buckets);
            }
            self.size -= 1;
            return true;
        }

        fn clear() {
            for uint::range(0, self.buckets.len()) |idx| {
                self.buckets[idx] = none;
            }
            self.size = 0;
        }
    }

    priv impl<K,V> &LinearMap<K,V> {
        fn search(hash: uint, op: fn(x: &option<Bucket<K,V>>) -> bool) {
            let _ = self.bucket_sequence(hash, |i| op(&self.buckets[i]));
        }
    }

    impl<K,V> &const LinearMap<K,V> {
        pure fn len() -> uint {
            self.size
        }

        pure fn is_empty() -> bool {
            self.len() == 0
        }

        fn contains_key(k: &K) -> bool {
            match self.bucket_for_key(self.buckets, k) {
              FoundEntry(_) => {true}
              TableFull | FoundHole(_) => {false}
            }
        }
    }

    impl<K,V: copy> &const LinearMap<K,V> {
        fn find(k: &K) -> option<V> {
            match self.bucket_for_key(self.buckets, k) {
              FoundEntry(idx) => {
                match check self.buckets[idx] {
                  some(bkt) => {some(copy bkt.value)}
                }
              }
              TableFull | FoundHole(_) => {
                none
              }
            }
        }

        fn get(k: &K) -> V {
            let value = self.find(k);
            if value.is_none() {
                fail fmt!{"No entry found for key: %?", k};
            }
            option::unwrap(value)
        }

    }

    impl<K,V> &LinearMap<K,V> {
        /*
        FIXME(#3148)--region inference fails to capture needed deps

        fn find_ref(k: &K) -> option<&self/V> {
            match self.bucket_for_key(self.buckets, k) {
              FoundEntry(idx) => {
                match check self.buckets[idx] {
                  some(ref bkt) => some(&bkt.value)
                }
              }
              TableFull | FoundHole(_) => {
                none
              }
            }
        }
        */

        fn each_ref(blk: fn(k: &K, v: &V) -> bool) {
            for vec::each(self.buckets) |slot| {
                let mut broke = false;
                do slot.iter |bucket| {
                    if !blk(&bucket.key, &bucket.value) {
                        broke = true; // FIXME(#3064) just write "break;"
                    }
                }
                if broke { break; }
            }
        }
        fn each_key_ref(blk: fn(k: &K) -> bool) {
            self.each_ref(|k, _v| blk(k))
        }
        fn each_value_ref(blk: fn(v: &V) -> bool) {
            self.each_ref(|_k, v| blk(v))
        }
    }

    impl<K: copy, V: copy> &LinearMap<K,V> {
        fn each(blk: fn(+K,+V) -> bool) {
            self.each_ref(|k,v| blk(copy *k, copy *v));
        }
    }
    impl<K: copy, V> &LinearMap<K,V> {
        fn each_key(blk: fn(+K) -> bool) {
            self.each_key_ref(|k| blk(copy *k));
        }
    }
    impl<K, V: copy> &LinearMap<K,V> {
        fn each_value(blk: fn(+V) -> bool) {
            self.each_value_ref(|v| blk(copy *v));
        }
    }
}

#[test]
mod test {

    import linear::{LinearMap, linear_map};

    pure fn uint_hash(x: &uint) -> uint { *x }
    pure fn uint_eq(x: &uint, y: &uint) -> bool { *x == *y }

    fn int_linear_map<V>() -> LinearMap<uint,V> {
        return linear_map(uint_hash, uint_eq);
    }

    #[test]
    fn inserts() {
        let mut m = ~int_linear_map();
        assert m.insert(1, 2);
        assert m.insert(2, 4);
        assert m.get(&1) == 2;
        assert m.get(&2) == 4;
    }

    #[test]
    fn overwrite() {
        let mut m = ~int_linear_map();
        assert m.insert(1, 2);
        assert m.get(&1) == 2;
        assert !m.insert(1, 3);
        assert m.get(&1) == 3;
    }

    #[test]
    fn conflicts() {
        let mut m = ~linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
        assert m.insert(1, 2);
        assert m.insert(5, 3);
        assert m.insert(9, 4);
        assert m.get(&9) == 4;
        assert m.get(&5) == 3;
        assert m.get(&1) == 2;
    }

    #[test]
    fn conflict_remove() {
        let mut m = ~linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
        assert m.insert(1, 2);
        assert m.insert(5, 3);
        assert m.insert(9, 4);
        assert m.remove(&1);
        assert m.get(&9) == 4;
        assert m.get(&5) == 3;
    }

    #[test]
    fn empty() {
        let mut m = ~linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
        assert m.insert(1, 2);
        assert !m.is_empty();
        assert m.remove(&1);
        assert m.is_empty();
    }

    #[test]
    fn iterate() {
        let mut m = linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
        for uint::range(0, 32) |i| {
            assert (&mut m).insert(i, i*2);
        }
        let mut observed = 0;
        for (&m).each |k, v| {
            assert v == k*2;
            observed |= (1 << k);
        }
        assert observed == 0xFFFF_FFFF;
    }
}
<commit_msg>Comments only: update issue number for FIXME<commit_after>/*!

Sendable hash maps.  Very much a work in progress.

*/

/**
 * A function that returns a hash of a value
 *
 * The hash should concentrate entropy in the lower bits.
 */
type HashFn<K> = pure fn~(K) -> uint;
type EqFn<K> = pure fn~(K, K) -> bool;

/// Open addressing with linear probing.
mod linear {
    export LinearMap, linear_map, linear_map_with_capacity, public_methods;

    const initial_capacity: uint = 32u; // 2^5
    type Bucket<K,V> = {hash: uint, key: K, value: V};
    enum LinearMap<K,V> {
        LinearMap_({
            hashfn: pure fn~(x: &K) -> uint,
            eqfn: pure fn~(x: &K, y: &K) -> bool,
            resize_at: uint,
            size: uint,
            buckets: ~[option<Bucket<K,V>>]})
    }

    // FIXME(#3148) -- we could rewrite found_entry
    // to have type option<&bucket<K,V>> which would be nifty
    // However, that won't work until #3148 is fixed
    enum SearchResult {
        FoundEntry(uint), FoundHole(uint), TableFull
    }

    fn resize_at(capacity: uint) -> uint {
        ((capacity as float) * 3. / 4.) as uint
    }

    fn linear_map<K,V>(
        +hashfn: pure fn~(x: &K) -> uint,
        +eqfn: pure fn~(x: &K, y: &K) -> bool) -> LinearMap<K,V> {

        linear_map_with_capacity(hashfn, eqfn, 32)
    }

    fn linear_map_with_capacity<K,V>(
        +hashfn: pure fn~(x: &K) -> uint,
        +eqfn: pure fn~(x: &K, y: &K) -> bool,
        initial_capacity: uint) -> LinearMap<K,V> {

        LinearMap_({
            hashfn: hashfn,
            eqfn: eqfn,
            resize_at: resize_at(initial_capacity),
            size: 0,
            buckets: vec::from_fn(initial_capacity, |_i| none)})
    }

    priv impl<K, V> &const LinearMap<K,V> {
        #[inline(always)]
        pure fn to_bucket(h: uint) -> uint {
            // FIXME(#3041) borrow a more sophisticated technique here from
            // Gecko, for example borrowing from Knuth, as Eich so
            // colorfully argues for here:
            // https://bugzilla.mozilla.org/show_bug.cgi?id=743107#c22
            h % self.buckets.len()
        }

        #[inline(always)]
        pure fn next_bucket(idx: uint, len_buckets: uint) -> uint {
            let n = (idx + 1) % len_buckets;
            unsafe{ // argh. log not considered pure.
                debug!{"next_bucket(%?, %?) = %?", idx, len_buckets, n};
            }
            return n;
        }

        #[inline(always)]
        pure fn bucket_sequence(hash: uint, op: fn(uint) -> bool) -> uint {
            let start_idx = self.to_bucket(hash);
            let len_buckets = self.buckets.len();
            let mut idx = start_idx;
            loop {
                if !op(idx) {
                    return idx;
                }
                idx = self.next_bucket(idx, len_buckets);
                if idx == start_idx {
                    return start_idx;
                }
            }
        }

        #[inline(always)]
        pure fn bucket_for_key(
            buckets: &[option<Bucket<K,V>>],
            k: &K) -> SearchResult {

            let hash = self.hashfn(k);
            self.bucket_for_key_with_hash(buckets, hash, k)
        }

        #[inline(always)]
        pure fn bucket_for_key_with_hash(
            buckets: &[option<Bucket<K,V>>],
            hash: uint,
            k: &K) -> SearchResult {

            let _ = for self.bucket_sequence(hash) |i| {
                match buckets[i] {
                  some(bkt) => if bkt.hash == hash && self.eqfn(k, &bkt.key) {
                    return FoundEntry(i);
                  },
                  none => return FoundHole(i)
                }
            };
            return TableFull;
        }
    }

    priv impl<K,V> &mut LinearMap<K,V> {
        /// Expands the capacity of the array and re-inserts each
        /// of the existing buckets.
        fn expand() {
            let old_capacity = self.buckets.len();
            let new_capacity = old_capacity * 2;
            self.resize_at = ((new_capacity as float) * 3.0 / 4.0) as uint;

            let mut old_buckets = vec::from_fn(new_capacity, |_i| none);
            self.buckets <-> old_buckets;

            for uint::range(0, old_capacity) |i| {
                let mut bucket = none;
                bucket <-> old_buckets[i];
                if bucket.is_some() {
                    self.insert_bucket(bucket);
                }
            }
        }

        fn insert_bucket(+bucket: option<Bucket<K,V>>) {
            let {hash, key, value} <- option::unwrap(bucket);
            let _ = self.insert_internal(hash, key, value);
        }

        /// Inserts the key value pair into the buckets.
        /// Assumes that there will be a bucket.
        /// True if there was no previous entry with that key
        fn insert_internal(hash: uint, +k: K, +v: V) -> bool {
            match self.bucket_for_key_with_hash(self.buckets, hash, &k) {
              TableFull => {fail ~"Internal logic error";}
              FoundHole(idx) => {
                debug!{"insert fresh (%?->%?) at idx %?, hash %?",
                       k, v, idx, hash};
                self.buckets[idx] = some({hash: hash, key: k, value: v});
                self.size += 1;
                return true;
              }
              FoundEntry(idx) => {
                debug!{"insert overwrite (%?->%?) at idx %?, hash %?",
                       k, v, idx, hash};
                self.buckets[idx] = some({hash: hash, key: k, value: v});
                return false;
              }
            }
        }
    }

    impl<K,V> &mut LinearMap<K,V> {
        fn insert(+k: K, +v: V) -> bool {
            if self.size >= self.resize_at {
                // n.b.: We could also do this after searching, so
                // that we do not resize if this call to insert is
                // simply going to update a key in place.  My sense
                // though is that it's worse to have to search through
                // buckets to find the right spot twice than to just
                // resize in this corner case.
                self.expand();
            }

            let hash = self.hashfn(&k);
            self.insert_internal(hash, k, v)
        }

        fn remove(k: &K) -> bool {
            // Removing from an open-addressed hashtable
            // is, well, painful.  The problem is that
            // the entry may lie on the probe path for other
            // entries, so removing it would make you think that
            // those probe paths are empty.
            //
            // To address this we basically have to keep walking,
            // re-inserting entries we find until we reach an empty
            // bucket.  We know we will eventually reach one because
            // we insert one ourselves at the beginning (the removed
            // entry).
            //
            // I found this explanation elucidating:
            // http://www.maths.lse.ac.uk/Courses/MA407/del-hash.pdf

            let mut idx = match self.bucket_for_key(self.buckets, k) {
              TableFull | FoundHole(_) => {
                return false;
              }
              FoundEntry(idx) => {
                idx
              }
            };

            let len_buckets = self.buckets.len();
            self.buckets[idx] = none;
            idx = self.next_bucket(idx, len_buckets);
            while self.buckets[idx].is_some() {
                let mut bucket = none;
                bucket <-> self.buckets[idx];
                self.insert_bucket(bucket);
                idx = self.next_bucket(idx, len_buckets);
            }
            self.size -= 1;
            return true;
        }

        fn clear() {
            for uint::range(0, self.buckets.len()) |idx| {
                self.buckets[idx] = none;
            }
            self.size = 0;
        }
    }

    priv impl<K,V> &LinearMap<K,V> {
        fn search(hash: uint, op: fn(x: &option<Bucket<K,V>>) -> bool) {
            let _ = self.bucket_sequence(hash, |i| op(&self.buckets[i]));
        }
    }

    impl<K,V> &const LinearMap<K,V> {
        pure fn len() -> uint {
            self.size
        }

        pure fn is_empty() -> bool {
            self.len() == 0
        }

        fn contains_key(k: &K) -> bool {
            match self.bucket_for_key(self.buckets, k) {
              FoundEntry(_) => {true}
              TableFull | FoundHole(_) => {false}
            }
        }
    }

    impl<K,V: copy> &const LinearMap<K,V> {
        fn find(k: &K) -> option<V> {
            match self.bucket_for_key(self.buckets, k) {
              FoundEntry(idx) => {
                match check self.buckets[idx] {
                  some(bkt) => {some(copy bkt.value)}
                }
              }
              TableFull | FoundHole(_) => {
                none
              }
            }
        }

        fn get(k: &K) -> V {
            let value = self.find(k);
            if value.is_none() {
                fail fmt!{"No entry found for key: %?", k};
            }
            option::unwrap(value)
        }

    }

    impl<K,V> &LinearMap<K,V> {
        /*
        FIXME(#3148)--region inference fails to capture needed deps

        fn find_ref(k: &K) -> option<&self/V> {
            match self.bucket_for_key(self.buckets, k) {
              FoundEntry(idx) => {
                match check self.buckets[idx] {
                  some(ref bkt) => some(&bkt.value)
                }
              }
              TableFull | FoundHole(_) => {
                none
              }
            }
        }
        */

        fn each_ref(blk: fn(k: &K, v: &V) -> bool) {
            for vec::each(self.buckets) |slot| {
                let mut broke = false;
                do slot.iter |bucket| {
                    if !blk(&bucket.key, &bucket.value) {
                        broke = true; // FIXME(#3064) just write "break;"
                    }
                }
                if broke { break; }
            }
        }
        fn each_key_ref(blk: fn(k: &K) -> bool) {
            self.each_ref(|k, _v| blk(k))
        }
        fn each_value_ref(blk: fn(v: &V) -> bool) {
            self.each_ref(|_k, v| blk(v))
        }
    }

    impl<K: copy, V: copy> &LinearMap<K,V> {
        fn each(blk: fn(+K,+V) -> bool) {
            self.each_ref(|k,v| blk(copy *k, copy *v));
        }
    }
    impl<K: copy, V> &LinearMap<K,V> {
        fn each_key(blk: fn(+K) -> bool) {
            self.each_key_ref(|k| blk(copy *k));
        }
    }
    impl<K, V: copy> &LinearMap<K,V> {
        fn each_value(blk: fn(+V) -> bool) {
            self.each_value_ref(|v| blk(copy *v));
        }
    }
}

#[test]
mod test {

    import linear::{LinearMap, linear_map};

    pure fn uint_hash(x: &uint) -> uint { *x }
    pure fn uint_eq(x: &uint, y: &uint) -> bool { *x == *y }

    fn int_linear_map<V>() -> LinearMap<uint,V> {
        return linear_map(uint_hash, uint_eq);
    }

    #[test]
    fn inserts() {
        let mut m = ~int_linear_map();
        assert m.insert(1, 2);
        assert m.insert(2, 4);
        assert m.get(&1) == 2;
        assert m.get(&2) == 4;
    }

    #[test]
    fn overwrite() {
        let mut m = ~int_linear_map();
        assert m.insert(1, 2);
        assert m.get(&1) == 2;
        assert !m.insert(1, 3);
        assert m.get(&1) == 3;
    }

    #[test]
    fn conflicts() {
        let mut m = ~linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
        assert m.insert(1, 2);
        assert m.insert(5, 3);
        assert m.insert(9, 4);
        assert m.get(&9) == 4;
        assert m.get(&5) == 3;
        assert m.get(&1) == 2;
    }

    #[test]
    fn conflict_remove() {
        let mut m = ~linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
        assert m.insert(1, 2);
        assert m.insert(5, 3);
        assert m.insert(9, 4);
        assert m.remove(&1);
        assert m.get(&9) == 4;
        assert m.get(&5) == 3;
    }

    #[test]
    fn empty() {
        let mut m = ~linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
        assert m.insert(1, 2);
        assert !m.is_empty();
        assert m.remove(&1);
        assert m.is_empty();
    }

    #[test]
    fn iterate() {
        let mut m = linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
        for uint::range(0, 32) |i| {
            assert (&mut m).insert(i, i*2);
        }
        let mut observed = 0;
        for (&m).each |k, v| {
            assert v == k*2;
            observed |= (1 << k);
        }
        assert observed == 0xFFFF_FFFF;
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 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.

#[allow(deprecated_mode)];

use json;
use sha1;
use serialize::{Encoder, Encodable, Decoder, Decodable};
use sort;

use core::cell::Cell;
use core::cmp;
use core::either::{Either, Left, Right};
use core::io;
use core::comm::{oneshot, PortOne, send_one};
use core::pipes::recv;
use core::prelude::*;
use core::result;
use core::run;
use core::hashmap::linear::LinearMap;
use core::task;
use core::to_bytes;
use core::mutable::Mut;

/**
*
* This is a loose clone of the fbuild build system, made a touch more
* generic (not wired to special cases on files) and much less metaprogram-y
* due to rust's comparative weakness there, relative to python.
*
* It's based around _imperative bulids_ that happen to have some function
* calls cached. That is, it's _just_ a mechanism for describing cached
* functions. This makes it much simpler and smaller than a "build system"
* that produces an IR and evaluates it. The evaluation order is normal
* function calls. Some of them just return really quickly.
*
* A cached function consumes and produces a set of _works_. A work has a
* name, a kind (that determines how the value is to be checked for
* freshness) and a value. Works must also be (de)serializable. Some
* examples of works:
*
*    kind   name    value
*   ------------------------
*    cfg    os      linux
*    file   foo.c   <sha1>
*    url    foo.com <etag>
*
* Works are conceptually single units, but we store them most of the time
* in maps of the form (type,name) => value. These are WorkMaps.
*
* A cached function divides the works it's interested up into inputs and
* outputs, and subdivides those into declared (input) works and
* discovered (input and output) works.
*
* A _declared_ input or is one that is given to the workcache before
* any work actually happens, in the "prep" phase. Even when a function's
* work-doing part (the "exec" phase) never gets called, it has declared
* inputs, which can be checked for freshness (and potentially
* used to determine that the function can be skipped).
*
* The workcache checks _all_ works for freshness, but uses the set of
* discovered outputs from the _previous_ exec (which it will re-discover
* and re-record each time the exec phase runs).
*
* Therefore the discovered works cached in the db might be a
* mis-approximation of the current discoverable works, but this is ok for
* the following reason: we assume that if an artifact A changed from
* depending on B,C,D to depending on B,C,D,E, then A itself changed (as
* part of the change-in-dependencies), so we will be ok.
*
* Each function has a single discriminated output work called its _result_.
* This is only different from other works in that it is returned, by value,
* from a call to the cacheable function; the other output works are used in
* passing to invalidate dependencies elsewhere in the cache, but do not
* otherwise escape from a function invocation. Most functions only have one
* output work anyways.
*
* A database (the central store of a workcache) stores a mappings:
*
* (fn_name,{declared_input}) => ({discovered_input},
*                                {discovered_output},result)
*
* (Note: fbuild, which workcache is based on, has the concept of a declared
* output as separate from a discovered output. This distinction exists only
* as an artifact of how fbuild works: via annotations on function types
* and metaprogramming, with explicit dependency declaration as a fallback.
* Workcache is more explicit about dependencies, and as such treats all
* outputs the same, as discovered-during-the-last-run.)
*
*/

#[deriving(Eq)]
#[auto_encode]
#[auto_decode]
struct WorkKey {
    kind: ~str,
    name: ~str
}

impl to_bytes::IterBytes for WorkKey {
    #[inline(always)]
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        let mut flag = true;
        self.kind.iter_bytes(lsb0, |bytes| {flag = f(bytes); flag});
        if !flag { return; }
        self.name.iter_bytes(lsb0, f);
    }
}

impl cmp::Ord for WorkKey {
    fn lt(&self, other: &WorkKey) -> bool {
        self.kind < other.kind ||
            (self.kind == other.kind &&
             self.name < other.name)
    }
    fn le(&self, other: &WorkKey) -> bool {
        self.lt(other) || self.eq(other)
    }
    fn ge(&self, other: &WorkKey) -> bool {
        self.gt(other) || self.eq(other)
    }
    fn gt(&self, other: &WorkKey) -> bool {
        ! self.le(other)
    }
}

pub impl WorkKey {
    fn new(kind: &str, name: &str) -> WorkKey {
    WorkKey { kind: kind.to_owned(), name: name.to_owned() }
    }
}

struct WorkMap(LinearMap<WorkKey, ~str>);

impl WorkMap {
    fn new() -> WorkMap { WorkMap(LinearMap::new()) }
}

impl<S:Encoder> Encodable<S> for WorkMap {
    fn encode(&self, s: &S) {
        let mut d = ~[];
        for self.each |&(k, v)| {
            d.push((copy *k, copy *v))
        }
        sort::tim_sort(d);
        d.encode(s)
    }
}

impl<D:Decoder> Decodable<D> for WorkMap {
    fn decode(d: &D) -> WorkMap {
        let v : ~[(WorkKey,~str)] = Decodable::decode(d);
        let mut w = WorkMap::new();
        for v.each |&(k, v)| {
            w.insert(copy k, copy v);
        }
        w
    }
}

struct Database {
    db_filename: Path,
    db_cache: LinearMap<~str, ~str>,
    mut db_dirty: bool
}

pub impl Database {
    fn prepare(&mut self,
               fn_name: &str,
               declared_inputs: &WorkMap) -> Option<(WorkMap, WorkMap, ~str)>
    {
        let k = json_encode(&(fn_name, declared_inputs));
        match self.db_cache.find(&k) {
            None => None,
            Some(v) => Some(json_decode(*v))
        }
    }

    fn cache(&mut self,
             fn_name: &str,
             declared_inputs: &WorkMap,
             discovered_inputs: &WorkMap,
             discovered_outputs: &WorkMap,
             result: &str) {
        let k = json_encode(&(fn_name, declared_inputs));
        let v = json_encode(&(discovered_inputs,
                              discovered_outputs,
                              result));
        self.db_cache.insert(k,v);
        self.db_dirty = true
    }
}

struct Logger {
    // FIXME #4432: Fill in
    a: ()
}

pub impl Logger {
    fn info(&self, i: &str) {
        io::println(~"workcache: " + i.to_owned());
    }
}

struct Context {
    db: @Mut<Database>,
    logger: @Mut<Logger>,
    cfg: @json::Object,
    freshness: LinearMap<~str,@fn(&str,&str)->bool>
}

struct Prep {
    ctxt: @Context,
    fn_name: ~str,
    declared_inputs: WorkMap,
}

struct Exec {
    discovered_inputs: WorkMap,
    discovered_outputs: WorkMap
}

struct Work<T> {
    prep: @Mut<Prep>,
    res: Option<Either<T,PortOne<(Exec,T)>>>
}

fn json_encode<T:Encodable<json::Encoder>>(t: &T) -> ~str {
    do io::with_str_writer |wr| {
        t.encode(&json::Encoder(wr));
    }
}

// FIXME(#5121)
fn json_decode<T:Decodable<json::Decoder>>(s: &str) -> T {
    do io::with_str_reader(s) |rdr| {
        let j = result::unwrap(json::from_reader(rdr));
        Decodable::decode(&json::Decoder(j))
    }
}

fn digest<T:Encodable<json::Encoder>>(t: &T) -> ~str {
    let mut sha = sha1::sha1();
    sha.input_str(json_encode(t));
    sha.result_str()
}

fn digest_file(path: &Path) -> ~str {
    let mut sha = sha1::sha1();
    let s = io::read_whole_file_str(path);
    sha.input_str(*s.get_ref());
    sha.result_str()
}

pub impl Context {

    fn new(db: @Mut<Database>,
                  lg: @Mut<Logger>,
                  cfg: @json::Object) -> Context {
        Context {
            db: db,
            logger: lg,
            cfg: cfg,
            freshness: LinearMap::new()
        }
    }

    fn prep<T:Owned +
              Encodable<json::Encoder> +
              Decodable<json::Decoder>>( // FIXME(#5121)
                  @self,
                  fn_name:&str,
                  blk: &fn(@Mut<Prep>)->Work<T>) -> Work<T> {
        let p = @Mut(Prep {
            ctxt: self,
            fn_name: fn_name.to_owned(),
            declared_inputs: WorkMap::new()
        });
        blk(p)
    }
}

trait TPrep {
    fn declare_input(&self, kind:&str, name:&str, val:&str);
    fn is_fresh(&self, cat:&str, kind:&str, name:&str, val:&str) -> bool;
    fn all_fresh(&self, cat:&str, map:&WorkMap) -> bool;
    fn exec<T:Owned +
              Encodable<json::Encoder> +
              Decodable<json::Decoder>>( // FIXME(#5121)
        &self, blk: ~fn(&Exec) -> T) -> Work<T>;
}

impl TPrep for @Mut<Prep> {
    fn declare_input(&self, kind:&str, name:&str, val:&str) {
        do self.borrow_mut |p| {
            p.declared_inputs.insert(WorkKey::new(kind, name),
                                     val.to_owned());
        }
    }

    fn is_fresh(&self, cat: &str, kind: &str,
                name: &str, val: &str) -> bool {
        do self.borrow_imm |p| {
            let k = kind.to_owned();
            let f = (*p.ctxt.freshness.get(&k))(name, val);
            do p.ctxt.logger.borrow_imm |lg| {
                if f {
                    lg.info(fmt!("%s %s:%s is fresh",
                                 cat, kind, name));
                } else {
                    lg.info(fmt!("%s %s:%s is not fresh",
                                 cat, kind, name))
                }
            }
            f
        }
    }

    fn all_fresh(&self, cat: &str, map: &WorkMap) -> bool {
        for map.each |&(k, v)| {
            if ! self.is_fresh(cat, k.kind, k.name, *v) {
                return false;
            }
        }
        return true;
    }

    fn exec<T:Owned +
              Encodable<json::Encoder> +
              Decodable<json::Decoder>>( // FIXME(#5121)
            &self, blk: ~fn(&Exec) -> T) -> Work<T> {
        let mut bo = Some(blk);

        do self.borrow_imm |p| {
            let cached = do p.ctxt.db.borrow_mut |db| {
                db.prepare(p.fn_name, &p.declared_inputs)
            };

            match cached {
                Some((ref disc_in, ref disc_out, ref res))
                if self.all_fresh("declared input",
                                  &p.declared_inputs) &&
                self.all_fresh("discovered input", disc_in) &&
                self.all_fresh("discovered output", disc_out) => {
                    Work::new(*self, Left(json_decode(*res)))
                }

                _ => {
                    let (chan, port) = oneshot::init();
                    let mut blk = None;
                    blk <-> bo;
                    let blk = blk.unwrap();
                    let chan = Cell(chan);
                    do task::spawn || {
                        let exe = Exec {
                            discovered_inputs: WorkMap::new(),
                            discovered_outputs: WorkMap::new(),
                        };
                        let chan = chan.take();
                        let v = blk(&exe);
                        send_one(chan, (exe, v));
                    }

                    Work::new(*self, Right(port))
                }
            }
        }
    }
}

pub impl<T:Owned +
         Encodable<json::Encoder> +
         Decodable<json::Decoder>> Work<T> { // FIXME(#5121)
    fn new(p: @Mut<Prep>, e: Either<T,PortOne<(Exec,T)>>) -> Work<T> {
        Work { prep: p, res: Some(e) }
    }
}

// FIXME (#3724): movable self. This should be in impl Work.
fn unwrap<T:Owned +
            Encodable<json::Encoder> +
            Decodable<json::Decoder>>( // FIXME(#5121)
        w: Work<T>) -> T {
    let mut ww = w;
    let mut s = None;

    ww.res <-> s;

    match s {
        None => fail!(),
        Some(Left(v)) => v,
        Some(Right(port)) => {
            let (exe, v) = match recv(port) {
                oneshot::send(data) => data
            };

            let s = json_encode(&v);

            do ww.prep.borrow_imm |p| {
                do p.ctxt.db.borrow_mut |db| {
                    db.cache(p.fn_name,
                             &p.declared_inputs,
                             &exe.discovered_inputs,
                             &exe.discovered_outputs,
                             s);
                }
            }
            v
        }
    }
}

//#[test]
fn test() {
    use core::io::WriterUtil;

    let db = @Mut(Database { db_filename: Path("db.json"),
                             db_cache: LinearMap::new(),
                             db_dirty: false });
    let lg = @Mut(Logger { a: () });
    let cfg = @LinearMap::new();
    let cx = @Context::new(db, lg, cfg);
    let w:Work<~str> = do cx.prep("test1") |prep| {
        let pth = Path("foo.c");
        {
            let file = io::file_writer(&pth, [io::Create]).get();
            file.write_str("int main() { return 0; }");
        }

        prep.declare_input("file", pth.to_str(), digest_file(&pth));
        do prep.exec |_exe| {
            let out = Path("foo.o");
            run::run_program("gcc", [~"foo.c", ~"-o", out.to_str()]);
            out.to_str()
        }
    };
    let s = unwrap(w);
    io::println(s);
}
<commit_msg>Removed all uses of Mut from workcache, replaced with @mut<commit_after>// Copyright 2012 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.

#[allow(deprecated_mode)];

use json;
use sha1;
use serialize::{Encoder, Encodable, Decoder, Decodable};
use sort;

use core::cell::Cell;
use core::cmp;
use core::either::{Either, Left, Right};
use core::io;
use core::comm::{oneshot, PortOne, send_one};
use core::pipes::recv;
use core::prelude::*;
use core::result;
use core::run;
use core::hashmap::linear::LinearMap;
use core::task;
use core::to_bytes;

/**
*
* This is a loose clone of the fbuild build system, made a touch more
* generic (not wired to special cases on files) and much less metaprogram-y
* due to rust's comparative weakness there, relative to python.
*
* It's based around _imperative bulids_ that happen to have some function
* calls cached. That is, it's _just_ a mechanism for describing cached
* functions. This makes it much simpler and smaller than a "build system"
* that produces an IR and evaluates it. The evaluation order is normal
* function calls. Some of them just return really quickly.
*
* A cached function consumes and produces a set of _works_. A work has a
* name, a kind (that determines how the value is to be checked for
* freshness) and a value. Works must also be (de)serializable. Some
* examples of works:
*
*    kind   name    value
*   ------------------------
*    cfg    os      linux
*    file   foo.c   <sha1>
*    url    foo.com <etag>
*
* Works are conceptually single units, but we store them most of the time
* in maps of the form (type,name) => value. These are WorkMaps.
*
* A cached function divides the works it's interested up into inputs and
* outputs, and subdivides those into declared (input) works and
* discovered (input and output) works.
*
* A _declared_ input or is one that is given to the workcache before
* any work actually happens, in the "prep" phase. Even when a function's
* work-doing part (the "exec" phase) never gets called, it has declared
* inputs, which can be checked for freshness (and potentially
* used to determine that the function can be skipped).
*
* The workcache checks _all_ works for freshness, but uses the set of
* discovered outputs from the _previous_ exec (which it will re-discover
* and re-record each time the exec phase runs).
*
* Therefore the discovered works cached in the db might be a
* mis-approximation of the current discoverable works, but this is ok for
* the following reason: we assume that if an artifact A changed from
* depending on B,C,D to depending on B,C,D,E, then A itself changed (as
* part of the change-in-dependencies), so we will be ok.
*
* Each function has a single discriminated output work called its _result_.
* This is only different from other works in that it is returned, by value,
* from a call to the cacheable function; the other output works are used in
* passing to invalidate dependencies elsewhere in the cache, but do not
* otherwise escape from a function invocation. Most functions only have one
* output work anyways.
*
* A database (the central store of a workcache) stores a mappings:
*
* (fn_name,{declared_input}) => ({discovered_input},
*                                {discovered_output},result)
*
* (Note: fbuild, which workcache is based on, has the concept of a declared
* output as separate from a discovered output. This distinction exists only
* as an artifact of how fbuild works: via annotations on function types
* and metaprogramming, with explicit dependency declaration as a fallback.
* Workcache is more explicit about dependencies, and as such treats all
* outputs the same, as discovered-during-the-last-run.)
*
*/

#[deriving(Eq)]
#[auto_encode]
#[auto_decode]
struct WorkKey {
    kind: ~str,
    name: ~str
}

impl to_bytes::IterBytes for WorkKey {
    #[inline(always)]
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        let mut flag = true;
        self.kind.iter_bytes(lsb0, |bytes| {flag = f(bytes); flag});
        if !flag { return; }
        self.name.iter_bytes(lsb0, f);
    }
}

impl cmp::Ord for WorkKey {
    fn lt(&self, other: &WorkKey) -> bool {
        self.kind < other.kind ||
            (self.kind == other.kind &&
             self.name < other.name)
    }
    fn le(&self, other: &WorkKey) -> bool {
        self.lt(other) || self.eq(other)
    }
    fn ge(&self, other: &WorkKey) -> bool {
        self.gt(other) || self.eq(other)
    }
    fn gt(&self, other: &WorkKey) -> bool {
        ! self.le(other)
    }
}

pub impl WorkKey {
    fn new(kind: &str, name: &str) -> WorkKey {
    WorkKey { kind: kind.to_owned(), name: name.to_owned() }
    }
}

struct WorkMap(LinearMap<WorkKey, ~str>);

impl WorkMap {
    fn new() -> WorkMap { WorkMap(LinearMap::new()) }
}

impl<S:Encoder> Encodable<S> for WorkMap {
    fn encode(&self, s: &S) {
        let mut d = ~[];
        for self.each |&(k, v)| {
            d.push((copy *k, copy *v))
        }
        sort::tim_sort(d);
        d.encode(s)
    }
}

impl<D:Decoder> Decodable<D> for WorkMap {
    fn decode(d: &D) -> WorkMap {
        let v : ~[(WorkKey,~str)] = Decodable::decode(d);
        let mut w = WorkMap::new();
        for v.each |&(k, v)| {
            w.insert(copy k, copy v);
        }
        w
    }
}

struct Database {
    db_filename: Path,
    db_cache: LinearMap<~str, ~str>,
    db_dirty: bool
}

pub impl Database {
    fn prepare(&mut self,
               fn_name: &str,
               declared_inputs: &WorkMap) -> Option<(WorkMap, WorkMap, ~str)>
    {
        let k = json_encode(&(fn_name, declared_inputs));
        match self.db_cache.find(&k) {
            None => None,
            Some(v) => Some(json_decode(*v))
        }
    }

    fn cache(&mut self,
             fn_name: &str,
             declared_inputs: &WorkMap,
             discovered_inputs: &WorkMap,
             discovered_outputs: &WorkMap,
             result: &str) {
        let k = json_encode(&(fn_name, declared_inputs));
        let v = json_encode(&(discovered_inputs,
                              discovered_outputs,
                              result));
        self.db_cache.insert(k,v);
        self.db_dirty = true
    }
}

struct Logger {
    // FIXME #4432: Fill in
    a: ()
}

pub impl Logger {
    fn info(&self, i: &str) {
        io::println(~"workcache: " + i.to_owned());
    }
}

struct Context {
    db: @mut Database,
    logger: @mut Logger,
    cfg: @json::Object,
    freshness: LinearMap<~str,@fn(&str,&str)->bool>
}

struct Prep {
    ctxt: @Context,
    fn_name: ~str,
    declared_inputs: WorkMap,
}

struct Exec {
    discovered_inputs: WorkMap,
    discovered_outputs: WorkMap
}

struct Work<T> {
    prep: @mut Prep,
    res: Option<Either<T,PortOne<(Exec,T)>>>
}

fn json_encode<T:Encodable<json::Encoder>>(t: &T) -> ~str {
    do io::with_str_writer |wr| {
        t.encode(&json::Encoder(wr));
    }
}

// FIXME(#5121)
fn json_decode<T:Decodable<json::Decoder>>(s: &str) -> T {
    do io::with_str_reader(s) |rdr| {
        let j = result::unwrap(json::from_reader(rdr));
        Decodable::decode(&json::Decoder(j))
    }
}

fn digest<T:Encodable<json::Encoder>>(t: &T) -> ~str {
    let mut sha = sha1::sha1();
    sha.input_str(json_encode(t));
    sha.result_str()
}

fn digest_file(path: &Path) -> ~str {
    let mut sha = sha1::sha1();
    let s = io::read_whole_file_str(path);
    sha.input_str(*s.get_ref());
    sha.result_str()
}

pub impl Context {

    fn new(db: @mut Database,
                  lg: @mut Logger,
                  cfg: @json::Object) -> Context {
        Context {
            db: db,
            logger: lg,
            cfg: cfg,
            freshness: LinearMap::new()
        }
    }

    fn prep<T:Owned +
              Encodable<json::Encoder> +
              Decodable<json::Decoder>>( // FIXME(#5121)
                  @self,
                  fn_name:&str,
                  blk: &fn(@mut Prep)->Work<T>) -> Work<T> {
        let p = @mut Prep {
            ctxt: self,
            fn_name: fn_name.to_owned(),
            declared_inputs: WorkMap::new()
        };
        blk(p)
    }
}

trait TPrep {
    fn declare_input(&mut self, kind:&str, name:&str, val:&str);
    fn is_fresh(&self, cat:&str, kind:&str, name:&str, val:&str) -> bool;
    fn all_fresh(&self, cat:&str, map:&WorkMap) -> bool;
    fn exec<T:Owned +
              Encodable<json::Encoder> +
              Decodable<json::Decoder>>( // FIXME(#5121)
        &self, blk: ~fn(&Exec) -> T) -> Work<T>;
}

impl TPrep for Prep {
    fn declare_input(&mut self, kind:&str, name:&str, val:&str) {
        self.declared_inputs.insert(WorkKey::new(kind, name),
                                 val.to_owned());
    }

    fn is_fresh(&self, cat: &str, kind: &str,
                name: &str, val: &str) -> bool {
        let k = kind.to_owned();
        let f = (*self.ctxt.freshness.get(&k))(name, val);
        let lg = self.ctxt.logger;
            if f {
                lg.info(fmt!("%s %s:%s is fresh",
                             cat, kind, name));
            } else {
                lg.info(fmt!("%s %s:%s is not fresh",
                             cat, kind, name))
            }
        f
    }

    fn all_fresh(&self, cat: &str, map: &WorkMap) -> bool {
        for map.each |&(k, v)| {
            if ! self.is_fresh(cat, k.kind, k.name, *v) {
                return false;
            }
        }
        return true;
    }

    fn exec<T:Owned +
              Encodable<json::Encoder> +
              Decodable<json::Decoder>>( // FIXME(#5121)
            &self, blk: ~fn(&Exec) -> T) -> Work<T> {
        let mut bo = Some(blk);

        let cached = self.ctxt.db.prepare(self.fn_name, &self.declared_inputs);

        match cached {
            Some((ref disc_in, ref disc_out, ref res))
            if self.all_fresh("declared input",
                              &self.declared_inputs) &&
            self.all_fresh("discovered input", disc_in) &&
            self.all_fresh("discovered output", disc_out) => {
                Work::new(@mut *self, Left(json_decode(*res)))
            }

            _ => {
                let (chan, port) = oneshot::init();
                let mut blk = None;
                blk <-> bo;
                let blk = blk.unwrap();
                let chan = Cell(chan);

                do task::spawn || {
                    let exe = Exec {
                        discovered_inputs: WorkMap::new(),
                        discovered_outputs: WorkMap::new(),
                    };
                    let chan = chan.take();
                    let v = blk(&exe);
                    send_one(chan, (exe, v));
                }
                Work::new(@mut *self, Right(port))
            }
        }
    }
}

pub impl<T:Owned +
         Encodable<json::Encoder> +
         Decodable<json::Decoder>> Work<T> { // FIXME(#5121)
    fn new(p: @mut Prep, e: Either<T,PortOne<(Exec,T)>>) -> Work<T> {
        Work { prep: p, res: Some(e) }
    }
}

// FIXME (#3724): movable self. This should be in impl Work.
fn unwrap<T:Owned +
            Encodable<json::Encoder> +
            Decodable<json::Decoder>>( // FIXME(#5121)
        w: Work<T>) -> T {
    let mut ww = w;
    let mut s = None;

    ww.res <-> s;

    match s {
        None => fail!(),
        Some(Left(v)) => v,
        Some(Right(port)) => {
            let (exe, v) = match recv(port) {
                oneshot::send(data) => data
            };

            let s = json_encode(&v);

            let p = &*ww.prep;
            let db = p.ctxt.db;
            db.cache(p.fn_name,
                 &p.declared_inputs,
                 &exe.discovered_inputs,
                 &exe.discovered_outputs,
                 s);
            v
        }
    }
}

//#[test]
fn test() {
    use core::io::WriterUtil;

    let db = @mut Database { db_filename: Path("db.json"),
                             db_cache: LinearMap::new(),
                             db_dirty: false };
    let lg = @mut Logger { a: () };
    let cfg = @LinearMap::new();
    let cx = @Context::new(db, lg, cfg);
    let w:Work<~str> = do cx.prep("test1") |prep| {
        let pth = Path("foo.c");
        {
            let file = io::file_writer(&pth, [io::Create]).get();
            file.write_str("int main() { return 0; }");
        }

        prep.declare_input("file", pth.to_str(), digest_file(&pth));
        do prep.exec |_exe| {
            let out = Path("foo.o");
            run::run_program("gcc", [~"foo.c", ~"-o", out.to_str()]);
            out.to_str()
        }
    };
    let s = unwrap(w);
    io::println(s);
}
<|endoftext|>


<commit_before><commit_msg>feat: add some benches for rmp-serde<commit_after>#![feature(test)]

extern crate test;

extern crate serde;
extern crate rmp_serde;

use serde::{Serialize, Deserialize};

use test::{Bencher};

#[bench]
fn bench_strings_1000(bencher: &mut Bencher) {
    bench_strings(bencher, 1000)
}

#[bench]
fn bench_strings_5000(bencher: &mut Bencher) {
    bench_strings(bencher, 5000)
}

#[bench]
fn bench_strings_10000(bencher: &mut Bencher) {
    bench_strings(bencher, 10000)
}

fn bench_strings(bencher: &mut Bencher, size: usize) {
    let vec: Vec<String> = ::std::iter::repeat("abcdefghijklmnopqrstuvwxyz".into())
        .take(size)
        .collect();

    let mut buf = Vec::new();
    vec.serialize(&mut rmp_serde::Serializer::new(&mut buf)).unwrap();

    bencher.iter(|| {
        <Vec<String>>::deserialize(&mut rmp_serde::Deserializer::new(&buf[..])).unwrap();
    })
}
<|endoftext|>


<commit_before><commit_msg>Refactor to have distinct request/session secrets.<commit_after><|endoftext|>


<commit_before><commit_msg>	modified:   src/main.rs<commit_after><|endoftext|>


<commit_before><commit_msg>Using send instead of send_msg<commit_after><|endoftext|>


<commit_before><commit_msg>Cleaning up / organizing protobuf generation.<commit_after><|endoftext|>


<commit_before><commit_msg>Add note about integration testing<commit_after><|endoftext|>


<commit_before><commit_msg>Settings and help text<commit_after><|endoftext|>


<commit_before><commit_msg>`offset` and `size` fields are `u64`<commit_after><|endoftext|>