<commit_before>//! Muxed. A tmux project manager with no runtime dependencies.
extern crate common;
extern crate docopt;
extern crate edit;
extern crate load;
extern crate new;
extern crate snapshot;

use common::args::Args;
use docopt::Docopt;
use std::env;
use std::process::exit;

#[macro_export]
macro_rules! try_or_err (
    ($expr: expr) => ({
        match $expr {
            Ok(val) => val,
            Err(e) => {
                println!("Muxed ran in to a problem: {}", e);
                exit(1);
            }
        }
    })
);

static USAGE: &str = "
Usage:
    muxed [options] <project>
    muxed edit [options] <project>
    muxed new [options] <project>
    muxed snapshot [options] <project>
    muxed (-h | --help)
    muxed (-v | --version)

Flags:
    -d                  If you want to create a muxed session without connecting to it
    -f                  Overwrite existing file if one exists
    --debug             Prints debug information while executing (project opening only)
    -h, --help          Prints help information
    -v, --version       Prints version information

Options:
    -p <project_dir>    The directory your project config files live in. Defaults to ~/.muxed/
    -t <session>        The name of the running TMUX session to codify

Args:
    <project>           The name of your project to open

Subcommands:
    edit <project>                   Edit an existing project file
    new <project>                    To create a new project file
    snapshot -t <session> <project>  Capture a running session and create a config file for it
";

/// The main execution method.
/// Currently accepts a single option. The option represents a configuration
/// file in the same naming format. Given a project file name `projectName.yml`
/// in the `~/.muxed/` directory.
///
/// # Examples
///
/// ~/.muxed/projectName.yml
///
/// ```
/// root: ~/projects/muxed/
/// windows:
///     - cargo: "cargo build"
///     - vim: "vim ."
///     - git: ""
/// ```
///
/// You can run the command:
///
/// ```
/// $ ./muxed projectName
/// ```
pub fn main() {
    let mut input: std::env::Args = env::args();

    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.deserialize())
        .unwrap_or_else(|e| e.exit());

    if args.flag_v {
        println!("Muxed {}", env!("CARGO_PKG_VERSION"));
        exit(0);
    };

    if let Some(x) = input.nth(1) {
        match x.as_ref() {
            "edit" => try_or_err!(edit::exec(args)),
            "new" => try_or_err!(new::exec(args)),
            "snapshot" => try_or_err!(snapshot::exec(args)),
            _ => try_or_err!(load::exec(args)),
        }
    }
}
<commit_msg>Get a basic error message printing for this scenario. Think I want to try pushing this into docopt if possible, but might be hard<commit_after>//! Muxed. A tmux project manager with no runtime dependencies.
extern crate common;
extern crate docopt;
extern crate edit;
extern crate load;
extern crate new;
extern crate snapshot;

use common::args::Args;
use docopt::Docopt;
use std::env;
use std::process::exit;

#[macro_export]
macro_rules! try_or_err (
    ($expr: expr) => ({
        match $expr {
            Ok(val) => val,
            Err(e) => {
                println!("Muxed ran in to a problem: {}", e);
                exit(1);
            }
        }
    })
);

static DISALLOWED_PROJECT_NAMES: [&str; 3] = ["new", "edit", "load"];

static USAGE: &str = "
Usage:
    muxed edit [options] <project>
    muxed new [options] <project>
    muxed snapshot [options] <project>
    muxed load [options] <project>
    muxed [options] <project>
    muxed (-h | --help)
    muxed (-v | --version)

Flags:
    -d                  If you want to create a muxed session without connecting to it
    -f                  Overwrite existing file if one exists
    --debug             Prints debug information while executing (project opening only)
    -h, --help          Prints help information
    -v, --version       Prints version information

Options:
    -p <project_dir>    The directory your project config files live in. Defaults to ~/.muxed/
    -t <session>        The name of the running TMUX session to codify

Args:
    <project>           The name of your project to open

Subcommands:
    edit <project>                   Edit an existing project file
    new <project>                    To create a new project file
    snapshot -t <session> <project>  Capture a running session and create a config file for it
";

/// The main execution method.
/// Currently accepts a single option. The option represents a configuration
/// file in the same naming format. Given a project file name `projectName.yml`
/// in the `~/.muxed/` directory.
///
/// # Examples
///
/// ~/.muxed/projectName.yml
///
/// ```
/// root: ~/projects/muxed/
/// windows:
///     - cargo: "cargo build"
///     - vim: "vim ."
///     - git: ""
/// ```
///
/// You can run the command:
///
/// ```
/// $ ./muxed projectName
/// ```
pub fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.deserialize())
        .unwrap_or_else(|e| e.exit());

    if args.flag_v {
        println!("Muxed {}", env!("CARGO_PKG_VERSION"));
        exit(0);
    };

    if args.cmd_new {
        try_or_err!(new::exec(args))
    } else if args.cmd_edit {
        try_or_err!(edit::exec(args))
    } else if args.cmd_snapshot {
        try_or_err!(snapshot::exec(args))
    } else if DISALLOWED_PROJECT_NAMES.contains(&args.arg_project.as_ref()) {
        println!(
            "Tried to call sub-command {} without a project. Please specify a project name.",
            args.arg_project
        );
        exit(1);
    } else {
        try_or_err!(load::exec(args))
    }
}
<|endoftext|>


<commit_before>//! A Rust snippet runner.
//!
//! Please see [readme](https://github.com/stevedonovan/runner/blob/master/readme.md)
extern crate easy_shortcuts as es;
extern crate lapp;
use es::traits::*;
use std::process;
use std::env;
use std::fs;
use std::path::PathBuf;
use std::collections::HashMap;
use std::io::Write;

mod crate_utils;
mod platform;

use platform::{open,edit,EXE};

fn rustup_lib() -> String {
    es::shell("rustc --print sysroot") + "/lib"
}

// this will be initially written to ~/.cargo/.runner/prelude and
// can then be edited.
const PRELUDE: &'static str = "
#![allow(unused_imports)]
#![allow(dead_code)]
use std::fs;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::env;
use std::path::{PathBuf,Path};
#[allow(unused_macros)]
macro_rules! debug {
    ($x:expr) => {
        println!(\"{} = {:?}\",stringify!($x),$x);
    }
}

";

fn runner_directory() -> PathBuf {
    let mut home = env::home_dir().or_die("no home!");
    home.push(".cargo");
    home.push(".runner");
    home
}

fn cargo(args: &[&str]) {
    let res = process::Command::new("cargo")
        .args(args)
        .status()
        .or_die("can't run cargo");
    if ! res.success() {
        es::quit("cargo failed");
    }
}

const STATIC_CACHE: &str = "static-cache";
const DYNAMIC_CACHE: &str = "dy-cache";

fn static_cache_dir() -> PathBuf {
    runner_directory().join(STATIC_CACHE)
}

fn static_cache_dir_check(args: &lapp::Args) -> PathBuf {
    let static_cache = static_cache_dir();
    if ! static_cache.exists() {
        args.quit("please build static cache with --create first");
    }
    static_cache
}

fn build_static_cache() {
    cargo(&["build"]);
    cargo(&["build","--release"]);
    cargo(&["doc"]);
}

fn create_static_cache(crates: &[String], create: bool) {
    use std::io::prelude::*;
    let mut home = runner_directory();
    env::set_current_dir(&home).or_die("cannot change to home directory");
    if create {
        cargo(&["new","--bin",STATIC_CACHE]);
    }
    home.push(STATIC_CACHE);
    env::set_current_dir(&home).or_die("could not create static cache");
    {
        let mut deps = fs::OpenOptions::new().append(true)
            .open("Cargo.toml").or_die("could not append to cargo.toml");
        for c in crates {
            write!(deps,"{}=\"*\"\n",c).or_die("could not modify cargo.toml");
        }
    }
    build_static_cache();
}

// this is always called first and has the important role to ensure that
// runner's directory structure is created properly.
fn get_prelude() -> String {
    let home = runner_directory();
    let pristine = ! home.is_dir();
    if pristine {
        fs::create_dir(&home).or_die("cannot create runner directory");
    }
    let prelude = home.join("prelude");
    let bin = home.join("bin");
    if pristine {
        es::write_all(&prelude,PRELUDE);
        fs::create_dir(&home.join(DYNAMIC_CACHE)).or_die("cannot create dynamic cache");
    }
    if pristine || ! bin.is_dir() {
        fs::create_dir(&bin).or_die("cannot create output directory");
    }
    es::read_to_string(&prelude)
}

fn get_cache(build_static: bool, optimize: bool) -> PathBuf {
    let mut home = runner_directory();
    let scache;
    let cache = if build_static {
        let dir = if optimize {"release"} else {"debug"};
        scache = format!("{}/target/{}/deps",STATIC_CACHE,dir);
        &scache
    } else {DYNAMIC_CACHE};
    home.push(cache);
    home
}

fn add_aliases(aliases: Vec<String>) {
    if aliases.len() == 0 { return; }
    let alias_file = runner_directory().join("alias");
    let mut f = if alias_file.is_file() {
        fs::OpenOptions::new().append(true).open(&alias_file)
    } else {
        fs::File::create(&alias_file)
    }.or_die("cannot open runner alias file");

    for crate_alias in aliases {
        write!(f,"{}\n",crate_alias).or_die("cannot write to runner alias file");
    }
}

fn get_aliases() -> HashMap<String,String> {
    let alias_file = runner_directory().join("alias");
    if ! alias_file.is_file() { return HashMap::new(); }
	es::lines(es::open(&alias_file))
      .filter_map(|s| s.split_at_delim('=').trim()) // split into (String,String)
	  .to_map()
}

fn massage_snippet(code: String, prelude: String, extern_crates: Vec<String>) -> String {
    fn indent_line(line: &str) -> String {
        format!("    {}\n",line)
    }
    let mut prefix = prelude;
    let mut body = String::new();
    {
        if extern_crates.len() > 0 {
            let aliases = get_aliases();
            for c in extern_crates {
                prefix += &if let Some(aliased) = aliases.get(&c) {
                    format!("extern crate {} as {};",aliased,c)
                } else {
                    format!("extern crate {};",c)
                };
            }
        }
        let mut lines = code.lines();
        let mut first = true;
        for line in lines.by_ref() {
            let line = line.trim_left();
            if first { // files may start with #! shebang...
                if line.starts_with("#") {
                    continue;
                }
                first = false;
            }
            if line.starts_with("//") || line.starts_with("#[") ||
                line.starts_with("extern ") || line.starts_with("use ") {
                prefix += line;
                prefix.push('\n');
            } else {
                body += &indent_line(line);
                break;
            }
        }
        // and indent the rest!
        body.extend(lines.map(indent_line));
    }

    format!("{}
use std::error::Error;
fn run() -> Result<(),Box<Error>> {{
{}    Ok(())
}}
fn main() {{
    run().unwrap();
}}
        ",prefix,body)

}

const USAGE: &str = "
Compile and run small Rust snippets
  -s, --static build statically (default is dynamic)
  -O, --optimize optimized static build
  -e, --expression evaluate an expression
  -i, --iterator evaluate an iterator
  -n, --lines evaluate expression over stdin; 'line' is defined
  -x, --extern... (string) add an extern crate to the snippet

  Cache Management:
  --create (string...) initialize the static cache with crates
  --add  (string...) add new crates to the cache (after --create)
  --edit  edit the static cache Cargo.toml
  --build rebuild the static cache
  --doc  display
  --edit-prelude edit the default prelude for snippets
  --alias (string...) crate aliases in form alias=crate_name (used with -x)

  Dynamic compilation:
  -P, --crate-path show path of crate source in Cargo cache
  -C, --compile  compile crate dynamically (limited)

  <program> (string) Rust program, snippet or expression
  <args> (string...) arguments to pass to program
";

fn main() {
    let args = lapp::parse_args(USAGE);
    let prelude = get_prelude();

    let aliases = args.get_strings("alias");
    if aliases.len() > 0 {
        add_aliases(aliases);
        return;
    }

    if args.get_bool("edit-prelude") {
        let rdir = runner_directory().join("prelude");
        edit(&rdir);
        return;
    }

    // Static Cache Management
    let crates = args.get_strings("create");
    if crates.len() > 0 {
        create_static_cache(&crates,true);
        return;
    }
    let crates = args.get_strings("add");
    if crates.len() > 0 {
        static_cache_dir_check(&args);
        create_static_cache(&crates,false);
        return;
    }

    if args.get_bool("edit") || args.get_bool("build") || args.get_bool("doc") {
        let static_cache = static_cache_dir_check(&args);
        if args.get_bool("build") {
            env::set_current_dir(&static_cache).or_die("static cache wasn't a directory?");
            build_static_cache();
        } else
        if args.get_bool("doc") {
            let docs = static_cache.join("target/doc/static_cache/index.html");
            open(&docs);
        } else {
            let toml = static_cache.join("Cargo.toml");
            edit(&toml);
        }
        return;
    }

    let first_arg = args.get_string("program");
    let file = PathBuf::from(&first_arg);

    // Dynamically linking crates (experimental!)
    if args.get_bool("crate-path") || args.get_bool("compile") {
        let (crate_path,crate_name) = if file.exists() {
            let filename = crate_utils::path_file_name(&file);
            if file.is_dir() { // assumed to be Cargo directory
                if ! file.join("Cargo.toml").exists() {
                    args.quit("not a Cargo project directory");
                }
                (file.join("src/lib.rs"), filename)
            } else { // should be just a Rust source file
                if file.extension().or_die("expecting extension") != "rs" {
                    args.quit("expecting Rust source file");
                }
                let name = crate_utils::path_file_name(&file.with_extension(""));
                (file, name)
            }
        } else {
            (crate_utils::cache_path(&first_arg).join("src/lib.rs"), first_arg)
        };
        if args.get_bool("crate-path") {
            println!("{}",crate_path.display());
        } else {
            let valid_crate_name = crate_name.replace('-',"_");
            let cache = get_cache(false, false);
            process::Command::new("rustc")
                .args(&["-C","prefer-dynamic"]).args(&["-C","debuginfo=0"])
                .arg("-L").arg(&cache)
                .args(&["--crate-type","dylib"])
                .arg("--out-dir").arg(&cache)
                .arg("--crate-name").arg(&valid_crate_name)
                .arg(crate_path)
           .status().or_die("can't run rustc");
        }
        return;
    }

    let build_static = args.get_bool("static");
    let optimize = args.get_bool("optimize");

    // we'll pass rest of arguments to program
    let program_args = args.get_strings("args");

    let cache = get_cache(build_static, optimize);

    let mut snippet = false;
    let mut code = if args.get_bool("expression") {
        // Evaluating an expression: just print it out.
        format!("println!(\"{{:?}}\",{});", first_arg)
    } else
    if args.get_bool("iterator") {
        // The expression is anything that implements IntoIterator
        format!("let iter = {};\n for val in iter {{ println!(\"{{:?}}\",val);}}", first_arg)
    } else
    if args.get_bool("lines") {
        // The variable 'line' is available to an expression, evaluated for each line in stdin
        format!("
            let stdin = io::stdin();
            for line in stdin.lock().lines() {{
                let line = line?;
                let val = {};
                println!(\"{{:?}}\",val);
            }}
            ", first_arg)
    } else { // otherwise, just a file
        snippet = true;
        es::read_to_string(&file)
    };

    // proper Rust programs are accepted (this is a bit rough)
    if code.find("fn main").is_none() {
        code = massage_snippet(code,prelude, args.get_strings("extern"));
    }

    // we are going to put the expanded source and resulting exe in the runner bin dir
    let mut out_file = runner_directory().join("bin");
    if snippet {
        out_file.push(&file);
        out_file.set_extension("rs");
    } else {
        out_file.push("tmp.rs");
    }
    let mut program = out_file.clone();
    program.set_extension(EXE);

    es::write_all(&out_file,&code);

    let mut builder = process::Command::new("rustc");
    if ! build_static {
        builder.args(&["-C","prefer-dynamic"]).args(&["-C","debuginfo=0"]);
    } else {
        builder.arg(if optimize {"-O"} else {"-g"});
    }
    builder.arg("-L").arg(&cache);
    let status = builder.arg("-o").arg(&program)
        .arg(&out_file)
        .status().or_die("can't run rustc");
    if ! status.success() {
        return;
    }

    let mut builder = process::Command::new(&program);
    if ! build_static {
        builder.env("LD_LIBRARY_PATH",format!("{}:{}",rustup_lib(),cache.display()));
    }
    builder.args(&program_args)
        .status()
        .or_die(&format!("can't run program {:?}",program));

}

<commit_msg>empty lines are ignored when preprocessing directive lines<commit_after>//! A Rust snippet runner.
//!
//! Please see [readme](https://github.com/stevedonovan/runner/blob/master/readme.md)
extern crate easy_shortcuts as es;
extern crate lapp;
use es::traits::*;
use std::process;
use std::env;
use std::fs;
use std::path::PathBuf;
use std::collections::HashMap;
use std::io::Write;

mod crate_utils;
mod platform;

use platform::{open,edit,EXE};

fn rustup_lib() -> String {
    es::shell("rustc --print sysroot") + "/lib"
}

// this will be initially written to ~/.cargo/.runner/prelude and
// can then be edited.
const PRELUDE: &'static str = "
#![allow(unused_imports)]
#![allow(dead_code)]
use std::fs;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::env;
use std::path::{PathBuf,Path};
#[allow(unused_macros)]
macro_rules! debug {
    ($x:expr) => {
        println!(\"{} = {:?}\",stringify!($x),$x);
    }
}

";

fn runner_directory() -> PathBuf {
    let mut home = env::home_dir().or_die("no home!");
    home.push(".cargo");
    home.push(".runner");
    home
}

fn cargo(args: &[&str]) {
    let res = process::Command::new("cargo")
        .args(args)
        .status()
        .or_die("can't run cargo");
    if ! res.success() {
        es::quit("cargo failed");
    }
}

const STATIC_CACHE: &str = "static-cache";
const DYNAMIC_CACHE: &str = "dy-cache";

fn static_cache_dir() -> PathBuf {
    runner_directory().join(STATIC_CACHE)
}

fn static_cache_dir_check(args: &lapp::Args) -> PathBuf {
    let static_cache = static_cache_dir();
    if ! static_cache.exists() {
        args.quit("please build static cache with --create first");
    }
    static_cache
}

fn build_static_cache() {
    cargo(&["build"]);
    cargo(&["build","--release"]);
    cargo(&["doc"]);
}

fn create_static_cache(crates: &[String], create: bool) {
    use std::io::prelude::*;
    let mut home = runner_directory();
    env::set_current_dir(&home).or_die("cannot change to home directory");
    if create {
        cargo(&["new","--bin",STATIC_CACHE]);
    }
    home.push(STATIC_CACHE);
    env::set_current_dir(&home).or_die("could not create static cache");
    {
        let mut deps = fs::OpenOptions::new().append(true)
            .open("Cargo.toml").or_die("could not append to cargo.toml");
        for c in crates {
            write!(deps,"{}=\"*\"\n",c).or_die("could not modify cargo.toml");
        }
    }
    build_static_cache();
}

// this is always called first and has the important role to ensure that
// runner's directory structure is created properly.
fn get_prelude() -> String {
    let home = runner_directory();
    let pristine = ! home.is_dir();
    if pristine {
        fs::create_dir(&home).or_die("cannot create runner directory");
    }
    let prelude = home.join("prelude");
    let bin = home.join("bin");
    if pristine {
        es::write_all(&prelude,PRELUDE);
        fs::create_dir(&home.join(DYNAMIC_CACHE)).or_die("cannot create dynamic cache");
    }
    if pristine || ! bin.is_dir() {
        fs::create_dir(&bin).or_die("cannot create output directory");
    }
    es::read_to_string(&prelude)
}

fn get_cache(build_static: bool, optimize: bool) -> PathBuf {
    let mut home = runner_directory();
    let scache;
    let cache = if build_static {
        let dir = if optimize {"release"} else {"debug"};
        scache = format!("{}/target/{}/deps",STATIC_CACHE,dir);
        &scache
    } else {DYNAMIC_CACHE};
    home.push(cache);
    home
}

fn add_aliases(aliases: Vec<String>) {
    if aliases.len() == 0 { return; }
    let alias_file = runner_directory().join("alias");
    let mut f = if alias_file.is_file() {
        fs::OpenOptions::new().append(true).open(&alias_file)
    } else {
        fs::File::create(&alias_file)
    }.or_die("cannot open runner alias file");

    for crate_alias in aliases {
        write!(f,"{}\n",crate_alias).or_die("cannot write to runner alias file");
    }
}

fn get_aliases() -> HashMap<String,String> {
    let alias_file = runner_directory().join("alias");
    if ! alias_file.is_file() { return HashMap::new(); }
	es::lines(es::open(&alias_file))
      .filter_map(|s| s.split_at_delim('=').trim()) // split into (String,String)
	  .to_map()
}

fn massage_snippet(code: String, prelude: String, extern_crates: Vec<String>) -> String {
    fn indent_line(line: &str) -> String {
        format!("    {}\n",line)
    }
    let mut prefix = prelude;
    let mut body = String::new();
    {
        if extern_crates.len() > 0 {
            let aliases = get_aliases();
            for c in extern_crates {
                prefix += &if let Some(aliased) = aliases.get(&c) {
                    format!("extern crate {} as {};",aliased,c)
                } else {
                    format!("extern crate {};",c)
                };
            }
        }
        let mut lines = code.lines();
        let mut first = true;
        for line in lines.by_ref() {
            let line = line.trim_left();
            if first { // files may start with #! shebang...
                if line.starts_with("#!") {
                    continue;
                }
                first = false;
            }
            if line.starts_with("//") || line.starts_with("#[") ||
                line.starts_with("extern ") || line.starts_with("use ") {
                prefix += line;
                prefix.push('\n');
            } else
            if line.len() > 0 {
                body += &indent_line(line);
                break;
            }
        }
        // and indent the rest!
        body.extend(lines.map(indent_line));
    }

    format!("{}
use std::error::Error;
fn run() -> Result<(),Box<Error>> {{
{}    Ok(())
}}
fn main() {{
    run().unwrap();
}}
        ",prefix,body)

}

const USAGE: &str = "
Compile and run small Rust snippets
  -s, --static build statically (default is dynamic)
  -O, --optimize optimized static build
  -e, --expression evaluate an expression
  -i, --iterator evaluate an iterator
  -n, --lines evaluate expression over stdin; 'line' is defined
  -x, --extern... (string) add an extern crate to the snippet

  Cache Management:
  --create (string...) initialize the static cache with crates
  --add  (string...) add new crates to the cache (after --create)
  --edit  edit the static cache Cargo.toml
  --build rebuild the static cache
  --doc  display
  --edit-prelude edit the default prelude for snippets
  --alias (string...) crate aliases in form alias=crate_name (used with -x)

  Dynamic compilation:
  -P, --crate-path show path of crate source in Cargo cache
  -C, --compile  compile crate dynamically (limited)

  <program> (string) Rust program, snippet or expression
  <args> (string...) arguments to pass to program
";

fn main() {
    let args = lapp::parse_args(USAGE);
    let prelude = get_prelude();

    let aliases = args.get_strings("alias");
    if aliases.len() > 0 {
        add_aliases(aliases);
        return;
    }

    if args.get_bool("edit-prelude") {
        let rdir = runner_directory().join("prelude");
        edit(&rdir);
        return;
    }

    // Static Cache Management
    let crates = args.get_strings("create");
    if crates.len() > 0 {
        create_static_cache(&crates,true);
        return;
    }
    let crates = args.get_strings("add");
    if crates.len() > 0 {
        static_cache_dir_check(&args);
        create_static_cache(&crates,false);
        return;
    }

    if args.get_bool("edit") || args.get_bool("build") || args.get_bool("doc") {
        let static_cache = static_cache_dir_check(&args);
        if args.get_bool("build") {
            env::set_current_dir(&static_cache).or_die("static cache wasn't a directory?");
            build_static_cache();
        } else
        if args.get_bool("doc") {
            let docs = static_cache.join("target/doc/static_cache/index.html");
            open(&docs);
        } else {
            let toml = static_cache.join("Cargo.toml");
            edit(&toml);
        }
        return;
    }

    let first_arg = args.get_string("program");
    let file = PathBuf::from(&first_arg);

    // Dynamically linking crates (experimental!)
    if args.get_bool("crate-path") || args.get_bool("compile") {
        let (crate_path,crate_name) = if file.exists() {
            let filename = crate_utils::path_file_name(&file);
            if file.is_dir() { // assumed to be Cargo directory
                if ! file.join("Cargo.toml").exists() {
                    args.quit("not a Cargo project directory");
                }
                (file.join("src/lib.rs"), filename)
            } else { // should be just a Rust source file
                if file.extension().or_die("expecting extension") != "rs" {
                    args.quit("expecting Rust source file");
                }
                let name = crate_utils::path_file_name(&file.with_extension(""));
                (file, name)
            }
        } else {
            (crate_utils::cache_path(&first_arg).join("src/lib.rs"), first_arg)
        };
        if args.get_bool("crate-path") {
            println!("{}",crate_path.display());
        } else {
            let valid_crate_name = crate_name.replace('-',"_");
            let cache = get_cache(false, false);
            process::Command::new("rustc")
                .args(&["-C","prefer-dynamic"]).args(&["-C","debuginfo=0"])
                .arg("-L").arg(&cache)
                .args(&["--crate-type","dylib"])
                .arg("--out-dir").arg(&cache)
                .arg("--crate-name").arg(&valid_crate_name)
                .arg(crate_path)
           .status().or_die("can't run rustc");
        }
        return;
    }

    let build_static = args.get_bool("static");
    let optimize = args.get_bool("optimize");

    // we'll pass rest of arguments to program
    let program_args = args.get_strings("args");

    let cache = get_cache(build_static, optimize);

    let mut snippet = false;
    let mut code = if args.get_bool("expression") {
        // Evaluating an expression: just print it out.
        format!("println!(\"{{:?}}\",{});", first_arg)
    } else
    if args.get_bool("iterator") {
        // The expression is anything that implements IntoIterator
        format!("let iter = {};\n for val in iter {{ println!(\"{{:?}}\",val);}}", first_arg)
    } else
    if args.get_bool("lines") {
        // The variable 'line' is available to an expression, evaluated for each line in stdin
        format!("
            let stdin = io::stdin();
            for line in stdin.lock().lines() {{
                let line = line?;
                let val = {};
                println!(\"{{:?}}\",val);
            }}
            ", first_arg)
    } else { // otherwise, just a file
        snippet = true;
        es::read_to_string(&file)
    };

    // proper Rust programs are accepted (this is a bit rough)
    if code.find("fn main").is_none() {
        code = massage_snippet(code,prelude, args.get_strings("extern"));
    }

    // we are going to put the expanded source and resulting exe in the runner bin dir
    let mut out_file = runner_directory().join("bin");
    if snippet {
        out_file.push(&file);
        out_file.set_extension("rs");
    } else {
        out_file.push("tmp.rs");
    }
    let mut program = out_file.clone();
    program.set_extension(EXE);

    es::write_all(&out_file,&code);

    let mut builder = process::Command::new("rustc");
    if ! build_static {
        builder.args(&["-C","prefer-dynamic"]).args(&["-C","debuginfo=0"]);
    } else {
        builder.arg(if optimize {"-O"} else {"-g"});
    }
    builder.arg("-L").arg(&cache);
    let status = builder.arg("-o").arg(&program)
        .arg(&out_file)
        .status().or_die("can't run rustc");
    if ! status.success() {
        return;
    }

    let mut builder = process::Command::new(&program);
    if ! build_static {
        builder.env("LD_LIBRARY_PATH",format!("{}:{}",rustup_lib(),cache.display()));
    }
    builder.args(&program_args)
        .status()
        .or_die(&format!("can't run program {:?}",program));

}

<|endoftext|>


<commit_before>extern crate cargo_update;
extern crate tabwriter;
extern crate lazysort;
extern crate regex;
extern crate git2;

use std::process::{Command, exit};
use std::io::{Write, stdout};
use tabwriter::TabWriter;
use lazysort::SortedBy;
use std::fmt::Display;
use git2::Repository;
#[cfg(target_os="windows")]
use std::fs::File;
use regex::Regex;
use std::env;
use std::fs;

fn main() {
    let result = actual_main().err().unwrap_or(0);
    exit(result);
}

fn actual_main() -> Result<(), i32> {
    let opts = cargo_update::Options::parse();

    if cfg!(target_os = "windows") {
        let old_version_r = Regex::new(r"cargo-install-update\.exe-v.+").unwrap();
        for old_version in fs::read_dir(env::current_exe().unwrap().parent().unwrap().canonicalize().unwrap())
            .unwrap()
            .map(Result::unwrap)
            .filter(|f| old_version_r.is_match(&f.file_name().into_string().unwrap())) {
            fs::remove_file(old_version.path()).unwrap();
        }
    }

    let crates_file = cargo_update::ops::resolve_crates_file(opts.crates_file.1.clone());
    let configuration = try!(cargo_update::ops::PackageConfig::read(&crates_file.with_file_name(".install_config.toml")));
    let mut packages = cargo_update::ops::installed_main_repo_packages(&crates_file);

    packages.retain(|p| configuration.get(&p.name).map(|p_cfg| opts.filter.iter().all(|f| f.matches(p_cfg))).unwrap_or(false));
    if !opts.to_update.is_empty() {
        packages = cargo_update::ops::intersect_packages(&packages, &opts.to_update, opts.install);
    }

    {
        // Searching for "" used to just update the registry, but since rustc 1.25.0/cargo 0.26.0, if not earlier, one just gets a dump
        // of every crate (https://github.com/nabijaczleweli/cargo-update/issues/79).
        //
        // Searching for a ZWNJ here will ensure we don't get any results (I'm pretty sure that's just forbidden, and if it's not and
        // someone makes one I'll make sure that that be the case).
        //
        // Another option would be (a) capturing the output (slower) or (b) passing "--limit 0" (not sure how well-supported that is
        // across past versions).
        let search_res = Command::new("cargo").arg("search").arg("\u{200C}").status().unwrap();
        if !search_res.success() {
            return Err(search_res.code().unwrap_or(-1));
        }
        println!("");
    }

    let registry = cargo_update::ops::get_index_path(&opts.cargo_dir.1);
    let registry_repo = try!(Repository::open(&registry).map_err(|_| {
        println!("Failed to open registry repository at {}.", registry.display());
        2
    }));
    let latest_registry = try!(registry_repo.revparse_single("origin/master").map_err(|_| {
        println!("Failed to read master branch of registry repository at {}.", registry.display());
        2
    }));

    for package in &mut packages {
        package.pull_version(&latest_registry.as_commit().unwrap().tree().unwrap(), &registry_repo);
    }

    {
        let mut out = TabWriter::new(stdout());
        writeln!(out, "Package\tInstalled\tLatest\tNeeds update").unwrap();
        for (package, package_target_version) in
            packages.iter()
                .map(|p| (p, configuration.get(&p.name).and_then(|c| c.target_version.as_ref())))
                .sorted_by(|&(ref lhs, lhstv), &(ref rhs, rhstv)| (!lhs.needs_update(lhstv), &lhs.name).cmp(&(!rhs.needs_update(rhstv), &rhs.name))) {
            write!(out, "{}\t", package.name).unwrap();
            if let Some(ref v) = package.version {
                write!(out, "v{}", v).unwrap();
            }
            if let Some(tv) = package_target_version {
                write!(out, "\t{}", tv).unwrap();
            } else if let Some(upd_v) = package.update_to_version() {
                write!(out, "\tv{}", upd_v).unwrap();
            } else {
                write!(out, "\tN/A").unwrap();
            }
            writeln!(out,
                     "\t{}",
                     if package.needs_update(package_target_version) {
                         "Yes"
                     } else {
                         "No"
                     })
                .unwrap();
        }
        writeln!(out, "").unwrap();
        out.flush().unwrap();
    }

    if opts.update {
        if !opts.force {
            packages.retain(|p| p.needs_update(configuration.get(&p.name).and_then(|c| c.target_version.as_ref())));
        }

        packages.retain(|pkg| pkg.update_to_version().is_some());

        if !packages.is_empty() {
            let (success_n, errored, result): (usize, Vec<String>, Option<i32>) = packages.into_iter()
                .map(|package| -> Result<(), (i32, String)> {
                    println!("{} {}",
                             if package.version.is_some() {
                                 "Updating"
                             } else {
                                 "Installing"
                             },
                             package.name);

                    if cfg!(target_os = "windows") && package.version.is_some() && package.name == "cargo-update" {
                        save_cargo_update_exec(package.version.as_ref().unwrap());
                    }

                    let install_res = if let Some(cfg) = configuration.get(&package.name) {
                            Command::new("cargo")
                                .args(&cfg.cargo_args()[..])
                                .arg(&package.name)
                                .arg("--vers")
                                .arg(if let Some(tv) = cfg.target_version.as_ref() {
                                    tv.to_string()
                                } else {
                                    package.update_to_version().unwrap().to_string()
                                })
                                .status()
                        } else {
                            Command::new("cargo")
                                .arg("install")
                                .arg("-f")
                                .arg(&package.name)
                                .arg("--vers")
                                .arg(package.update_to_version().unwrap().to_string())
                                .status()
                        }
                        .unwrap();

                    println!("");
                    if !install_res.success() {
                        if cfg!(target_os = "windows") && package.version.is_some() && package.name == "cargo-update" {
                            restore_cargo_update_exec(package.version.as_ref().unwrap());
                        }

                        Err((install_res.code().unwrap_or(-1), package.name))
                    } else {
                        Ok(())
                    }
                })
                .fold((0, vec![], None), |(s, mut e, r), p| match p {
                    Ok(()) => (s + 1, e, r),
                    Err((pr, pn)) => {
                        e.push(pn);
                        (s, e, r.or_else(|| Some(pr)))
                    }
                });

            println!("");
            println!("Updated {} package{}.", success_n, if success_n == 1 { "" } else { "s" });
            if !errored.is_empty() && result.is_some() {
                println!("Failed to update {}.", &errored.iter().fold("".to_string(), |s, e| s + ", " + e)[2..]);
                return Err(result.unwrap());
            }
        } else {
            println!("No packages need updating.");
        }
    }

    if opts.update_git {
        let mut packages = cargo_update::ops::installed_git_repo_packages(&crates_file);

        packages.retain(|p| configuration.get(&p.name).map(|p_cfg| opts.filter.iter().all(|f| f.matches(p_cfg))).unwrap_or(false));
        if !opts.to_update.is_empty() {
            packages.retain(|p| opts.to_update.iter().any(|u| p.name == u.0));
        }

        for package in &mut packages {
            package.pull_version(&opts.temp_dir.1);
        }

        {
            let mut out = TabWriter::new(stdout());
            writeln!(out, "Package\tInstalled\tLatest\tNeeds update").unwrap();
            for package in packages.iter()
                .sorted_by(|lhs, rhs| (!lhs.needs_update(), &lhs.name).cmp(&(!rhs.needs_update(), &rhs.name))) {
                writeln!(out,
                         "{}\t{}\t{}\t{}",
                         package.name,
                         package.id,
                         package.newest_id.as_ref().unwrap(),
                         if package.needs_update() { "Yes" } else { "No" })
                    .unwrap();
            }
            writeln!(out, "").unwrap();
            out.flush().unwrap();
        }

        if opts.update {
            if !opts.force {
                packages.retain(cargo_update::ops::GitRepoPackage::needs_update);
            }

            if !packages.is_empty() {
                let (success_n, errored, result): (usize, Vec<String>, Option<i32>) = packages.into_iter()
                    .map(|package| -> Result<(), (i32, String)> {
                        println!("Updating {} from {}", package.name, package.url);

                        if cfg!(target_os = "windows") && package.name == "cargo-update" {
                            save_cargo_update_exec(&package.id.to_string());
                        }

                        let install_res = if let Some(cfg) = configuration.get(&package.name) {
                                let mut cmd = Command::new("cargo");
                                cmd.args(&cfg.cargo_args()[..])
                                    .arg("--git")
                                    .arg(&package.url)
                                    .arg(&package.name);
                                if let Some(ref b) = package.branch.as_ref() {
                                    cmd.arg("--branch").arg(b);
                                }
                                cmd.status()
                            } else {
                                let mut cmd = Command::new("cargo");
                                cmd.arg("install")
                                    .arg("-f")
                                    .arg("--git")
                                    .arg(&package.url)
                                    .arg(&package.name);
                                if let Some(ref b) = package.branch.as_ref() {
                                    cmd.arg("--branch").arg(b);
                                }
                                cmd.status()
                            }
                            .unwrap();

                        println!("");
                        if !install_res.success() {
                            if cfg!(target_os = "windows") && package.name == "cargo-update" {
                                restore_cargo_update_exec(&package.id.to_string());
                            }

                            Err((install_res.code().unwrap_or(-1), package.name))
                        } else {
                            Ok(())
                        }
                    })
                    .fold((0, vec![], None), |(s, mut e, r), p| match p {
                        Ok(()) => (s + 1, e, r),
                        Err((pr, pn)) => {
                            e.push(pn);
                            (s, e, r.or_else(|| Some(pr)))
                        }
                    });

                println!("");
                println!("Updated {} git package{}.", success_n, if success_n == 1 { "" } else { "s" });
                if !errored.is_empty() && result.is_some() {
                    println!("Failed to update {}.", &errored.iter().fold("".to_string(), |s, e| s + ", " + e)[2..]);
                    return Err(result.unwrap());
                }
            } else {
                println!("No git packages need updating.");
            }
        }
    }

    Ok(())
}

/// This way the past-current exec will be "replaced" and we'll get no dupes in .cargo.toml
#[cfg(target_os="windows")]
fn save_cargo_update_exec<D: Display>(version: &D) {
    let cur_exe = env::current_exe().unwrap();
    fs::rename(&cur_exe, cur_exe.with_extension(format!("exe-v{}", version))).unwrap();
    File::create(cur_exe).unwrap();
}

#[cfg(target_os="windows")]
fn restore_cargo_update_exec<D: Display>(version: &D) {
    let cur_exe = env::current_exe().unwrap();
    fs::remove_file(&cur_exe).unwrap();
    fs::rename(cur_exe.with_extension(format!("exe-v{}", version)), cur_exe).unwrap();
}

#[cfg(not(target_os="windows"))]
fn save_cargo_update_exec<D: Display>(_: &D) {}

#[cfg(not(target_os="windows"))]
fn restore_cargo_update_exec<D: Display>(_: &D) {}
<commit_msg>Fix empty filter list filtering out everything<commit_after>extern crate cargo_update;
extern crate tabwriter;
extern crate lazysort;
extern crate regex;
extern crate git2;

use std::process::{Command, exit};
use std::io::{Write, stdout};
use tabwriter::TabWriter;
use lazysort::SortedBy;
use std::fmt::Display;
use git2::Repository;
#[cfg(target_os="windows")]
use std::fs::File;
use regex::Regex;
use std::env;
use std::fs;

fn main() {
    let result = actual_main().err().unwrap_or(0);
    exit(result);
}

fn actual_main() -> Result<(), i32> {
    let opts = cargo_update::Options::parse();

    if cfg!(target_os = "windows") {
        let old_version_r = Regex::new(r"cargo-install-update\.exe-v.+").unwrap();
        for old_version in fs::read_dir(env::current_exe().unwrap().parent().unwrap().canonicalize().unwrap())
            .unwrap()
            .map(Result::unwrap)
            .filter(|f| old_version_r.is_match(&f.file_name().into_string().unwrap())) {
            fs::remove_file(old_version.path()).unwrap();
        }
    }

    let crates_file = cargo_update::ops::resolve_crates_file(opts.crates_file.1.clone());
    let configuration = try!(cargo_update::ops::PackageConfig::read(&crates_file.with_file_name(".install_config.toml")));
    let mut packages = cargo_update::ops::installed_main_repo_packages(&crates_file);

    if !opts.filter.is_empty() {
        packages.retain(|p| configuration.get(&p.name).map(|p_cfg| opts.filter.iter().all(|f| f.matches(p_cfg))).unwrap_or(false));
    }
    if !opts.to_update.is_empty() {
        packages = cargo_update::ops::intersect_packages(&packages, &opts.to_update, opts.install);
    }

    {
        // Searching for "" used to just update the registry, but since rustc 1.25.0/cargo 0.26.0, if not earlier, one just gets a dump
        // of every crate (https://github.com/nabijaczleweli/cargo-update/issues/79).
        //
        // Searching for a ZWNJ here will ensure we don't get any results (I'm pretty sure that's just forbidden, and if it's not and
        // someone makes one I'll make sure that that be the case).
        //
        // Another option would be (a) capturing the output (slower) or (b) passing "--limit 0" (not sure how well-supported that is
        // across past versions).
        let search_res = Command::new("cargo").arg("search").arg("\u{200C}").status().unwrap();
        if !search_res.success() {
            return Err(search_res.code().unwrap_or(-1));
        }
        println!("");
    }

    let registry = cargo_update::ops::get_index_path(&opts.cargo_dir.1);
    let registry_repo = try!(Repository::open(&registry).map_err(|_| {
        println!("Failed to open registry repository at {}.", registry.display());
        2
    }));
    let latest_registry = try!(registry_repo.revparse_single("origin/master").map_err(|_| {
        println!("Failed to read master branch of registry repository at {}.", registry.display());
        2
    }));

    for package in &mut packages {
        package.pull_version(&latest_registry.as_commit().unwrap().tree().unwrap(), &registry_repo);
    }

    {
        let mut out = TabWriter::new(stdout());
        writeln!(out, "Package\tInstalled\tLatest\tNeeds update").unwrap();
        for (package, package_target_version) in
            packages.iter()
                .map(|p| (p, configuration.get(&p.name).and_then(|c| c.target_version.as_ref())))
                .sorted_by(|&(ref lhs, lhstv), &(ref rhs, rhstv)| (!lhs.needs_update(lhstv), &lhs.name).cmp(&(!rhs.needs_update(rhstv), &rhs.name))) {
            write!(out, "{}\t", package.name).unwrap();
            if let Some(ref v) = package.version {
                write!(out, "v{}", v).unwrap();
            }
            if let Some(tv) = package_target_version {
                write!(out, "\t{}", tv).unwrap();
            } else if let Some(upd_v) = package.update_to_version() {
                write!(out, "\tv{}", upd_v).unwrap();
            } else {
                write!(out, "\tN/A").unwrap();
            }
            writeln!(out,
                     "\t{}",
                     if package.needs_update(package_target_version) {
                         "Yes"
                     } else {
                         "No"
                     })
                .unwrap();
        }
        writeln!(out, "").unwrap();
        out.flush().unwrap();
    }

    if opts.update {
        if !opts.force {
            packages.retain(|p| p.needs_update(configuration.get(&p.name).and_then(|c| c.target_version.as_ref())));
        }

        packages.retain(|pkg| pkg.update_to_version().is_some());

        if !packages.is_empty() {
            let (success_n, errored, result): (usize, Vec<String>, Option<i32>) = packages.into_iter()
                .map(|package| -> Result<(), (i32, String)> {
                    println!("{} {}",
                             if package.version.is_some() {
                                 "Updating"
                             } else {
                                 "Installing"
                             },
                             package.name);

                    if cfg!(target_os = "windows") && package.version.is_some() && package.name == "cargo-update" {
                        save_cargo_update_exec(package.version.as_ref().unwrap());
                    }

                    let install_res = if let Some(cfg) = configuration.get(&package.name) {
                            Command::new("cargo")
                                .args(&cfg.cargo_args()[..])
                                .arg(&package.name)
                                .arg("--vers")
                                .arg(if let Some(tv) = cfg.target_version.as_ref() {
                                    tv.to_string()
                                } else {
                                    package.update_to_version().unwrap().to_string()
                                })
                                .status()
                        } else {
                            Command::new("cargo")
                                .arg("install")
                                .arg("-f")
                                .arg(&package.name)
                                .arg("--vers")
                                .arg(package.update_to_version().unwrap().to_string())
                                .status()
                        }
                        .unwrap();

                    println!("");
                    if !install_res.success() {
                        if cfg!(target_os = "windows") && package.version.is_some() && package.name == "cargo-update" {
                            restore_cargo_update_exec(package.version.as_ref().unwrap());
                        }

                        Err((install_res.code().unwrap_or(-1), package.name))
                    } else {
                        Ok(())
                    }
                })
                .fold((0, vec![], None), |(s, mut e, r), p| match p {
                    Ok(()) => (s + 1, e, r),
                    Err((pr, pn)) => {
                        e.push(pn);
                        (s, e, r.or_else(|| Some(pr)))
                    }
                });

            println!("");
            println!("Updated {} package{}.", success_n, if success_n == 1 { "" } else { "s" });
            if !errored.is_empty() && result.is_some() {
                println!("Failed to update {}.", &errored.iter().fold("".to_string(), |s, e| s + ", " + e)[2..]);
                return Err(result.unwrap());
            }
        } else {
            println!("No packages need updating.");
        }
    }

    if opts.update_git {
        let mut packages = cargo_update::ops::installed_git_repo_packages(&crates_file);

        if !opts.filter.is_empty() {
            packages.retain(|p| configuration.get(&p.name).map(|p_cfg| opts.filter.iter().all(|f| f.matches(p_cfg))).unwrap_or(false));
        }
        if !opts.to_update.is_empty() {
            packages.retain(|p| opts.to_update.iter().any(|u| p.name == u.0));
        }

        for package in &mut packages {
            package.pull_version(&opts.temp_dir.1);
        }

        {
            let mut out = TabWriter::new(stdout());
            writeln!(out, "Package\tInstalled\tLatest\tNeeds update").unwrap();
            for package in packages.iter()
                .sorted_by(|lhs, rhs| (!lhs.needs_update(), &lhs.name).cmp(&(!rhs.needs_update(), &rhs.name))) {
                writeln!(out,
                         "{}\t{}\t{}\t{}",
                         package.name,
                         package.id,
                         package.newest_id.as_ref().unwrap(),
                         if package.needs_update() { "Yes" } else { "No" })
                    .unwrap();
            }
            writeln!(out, "").unwrap();
            out.flush().unwrap();
        }

        if opts.update {
            if !opts.force {
                packages.retain(cargo_update::ops::GitRepoPackage::needs_update);
            }

            if !packages.is_empty() {
                let (success_n, errored, result): (usize, Vec<String>, Option<i32>) = packages.into_iter()
                    .map(|package| -> Result<(), (i32, String)> {
                        println!("Updating {} from {}", package.name, package.url);

                        if cfg!(target_os = "windows") && package.name == "cargo-update" {
                            save_cargo_update_exec(&package.id.to_string());
                        }

                        let install_res = if let Some(cfg) = configuration.get(&package.name) {
                                let mut cmd = Command::new("cargo");
                                cmd.args(&cfg.cargo_args()[..])
                                    .arg("--git")
                                    .arg(&package.url)
                                    .arg(&package.name);
                                if let Some(ref b) = package.branch.as_ref() {
                                    cmd.arg("--branch").arg(b);
                                }
                                cmd.status()
                            } else {
                                let mut cmd = Command::new("cargo");
                                cmd.arg("install")
                                    .arg("-f")
                                    .arg("--git")
                                    .arg(&package.url)
                                    .arg(&package.name);
                                if let Some(ref b) = package.branch.as_ref() {
                                    cmd.arg("--branch").arg(b);
                                }
                                cmd.status()
                            }
                            .unwrap();

                        println!("");
                        if !install_res.success() {
                            if cfg!(target_os = "windows") && package.name == "cargo-update" {
                                restore_cargo_update_exec(&package.id.to_string());
                            }

                            Err((install_res.code().unwrap_or(-1), package.name))
                        } else {
                            Ok(())
                        }
                    })
                    .fold((0, vec![], None), |(s, mut e, r), p| match p {
                        Ok(()) => (s + 1, e, r),
                        Err((pr, pn)) => {
                            e.push(pn);
                            (s, e, r.or_else(|| Some(pr)))
                        }
                    });

                println!("");
                println!("Updated {} git package{}.", success_n, if success_n == 1 { "" } else { "s" });
                if !errored.is_empty() && result.is_some() {
                    println!("Failed to update {}.", &errored.iter().fold("".to_string(), |s, e| s + ", " + e)[2..]);
                    return Err(result.unwrap());
                }
            } else {
                println!("No git packages need updating.");
            }
        }
    }

    Ok(())
}

/// This way the past-current exec will be "replaced" and we'll get no dupes in .cargo.toml
#[cfg(target_os="windows")]
fn save_cargo_update_exec<D: Display>(version: &D) {
    let cur_exe = env::current_exe().unwrap();
    fs::rename(&cur_exe, cur_exe.with_extension(format!("exe-v{}", version))).unwrap();
    File::create(cur_exe).unwrap();
}

#[cfg(target_os="windows")]
fn restore_cargo_update_exec<D: Display>(version: &D) {
    let cur_exe = env::current_exe().unwrap();
    fs::remove_file(&cur_exe).unwrap();
    fs::rename(cur_exe.with_extension(format!("exe-v{}", version)), cur_exe).unwrap();
}

#[cfg(not(target_os="windows"))]
fn save_cargo_update_exec<D: Display>(_: &D) {}

#[cfg(not(target_os="windows"))]
fn restore_cargo_update_exec<D: Display>(_: &D) {}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
#[macro_use]
extern crate log;

extern crate env_logger;
extern crate image;
extern crate nalgebra;
extern crate obj;
extern crate time;

extern crate genmesh;

mod camera;
mod draw;
mod shader;

use std::collections::HashMap;
use std::io::Read;
use std::fs::File;

use camera::Camera;
use draw::{Cube, Grid, GameObject};
use shader::ShaderType;

use glium::{glutin, Display, DisplayBuild, DrawError, Program, Surface};
use glium::glutin::{ElementState, VirtualKeyCode};

use nalgebra::{zero, BaseFloat, Vec3};

struct Scene {
    objects: Vec<Box<GameObject>>,
    camera: Camera,
}

impl Scene {
    fn new(camera: Camera) -> Self {
        Scene { camera: camera, objects: Vec::new() }
    }

    fn draw(&self, ctxt: &mut EngineContext) {
        let mut target = ctxt.display.draw();
        target.clear_color_and_depth((0., 0., 0., 1.), 1.);
        for obj in self.objects.iter() {
            ctxt.draw(&mut target, &self.camera, obj).unwrap();
        }
        target.finish().unwrap();
    }

    fn add<G: GameObject + 'static>(&mut self, object: G) {
        self.objects.push(Box::new(object));
    }
}

const RELATIVE_ROTATION: bool = true;

fn get_display_dim(display: &Display) -> (u32, u32) {
    match display.get_window().unwrap().get_inner_size() {
        Some(dim) => dim,
        None => panic!("Couldn't get window dimensions")
    }
}

pub struct EngineContext {
    display: Display,
    vertex_shader: String,
    shader_map: HashMap<ShaderType, String>,
}

impl EngineContext {
    pub fn new(display: Display) -> Self {
        let mut shader = String::new();
        File::open("shaders/vertex.glsl").unwrap().read_to_string(&mut shader).unwrap();
        EngineContext { display: display, vertex_shader: shader, shader_map: HashMap::new() }
    }

    pub fn draw<S: Surface>(&mut self, surface: &mut S, camera: &Camera,
                            obj: &Box<GameObject>) -> Result<(), DrawError> {
        let parent = obj.parent();
        let uniforms = obj.construct_uniforms(&camera);

        let &mut EngineContext { ref display, ref vertex_shader, ref mut shader_map } = self;
        let fragment_shader = Self::get_shader(shader_map, parent.shader_type);
        let program = Program::from_source(display, vertex_shader, fragment_shader, None).unwrap();
        surface.draw(&parent.vertex_buffer, parent.indices.clone(), &program, &uniforms,
                     &parent.draw_params)
    }

    fn get_shader(shader_map: &mut HashMap<ShaderType, String>, shader_type: ShaderType) -> &str {
        shader_map.entry(shader_type).or_insert_with(|| {
            let mut shader = String::new();
            File::open(shader_type.to_filename()).unwrap().read_to_string(&mut shader).unwrap();
            shader
        })
    }
}

fn main() {
    env_logger::init().unwrap();

    let display = glutin::WindowBuilder::new()
        .with_dimensions(800, 600)
        .with_title(format!("3D Cube"))
        .build_glium()
        .unwrap();

    let camera = {
        let (w, h) = get_display_dim(&display);
        let (w, h) = (w as f32, h as f32);
        Camera::new(Vec3::new(0., 0., 1.), w / h)
    };

    let mut scene = Scene::new(camera);
    scene.add(Grid::new(&display, 20));
    scene.add(Cube::new(&display, 1., zero()));

    let mut mouse_pressed = false;
    let mut old_mouse_coords = None;

    let mut ctxt = EngineContext::new(display);
    loop {
        scene.draw(&mut ctxt);

        for ev in ctxt.display.poll_events() {
            match ev {
                glutin::Event::KeyboardInput(ElementState::Pressed, _, Some(key)) => {
                    match key {
                        VirtualKeyCode::Up => scene.camera.translate(&Vec3::new(0., 0.05, 0.)),
                        VirtualKeyCode::Down => scene.camera.translate(&Vec3::new(0., -0.05, 0.)),
                        VirtualKeyCode::Left => scene.camera.translate(&Vec3::new(-0.05, 0., 0.)),
                        VirtualKeyCode::Right => scene.camera.translate(&Vec3::new(0.05, 0., 0.)),
                        VirtualKeyCode::R => {
                            scene.camera.set_pos(&Vec3::new(0., 0., 1.));
                            scene.camera.set_abs_rotation(0., 0.);
                            scene.camera.set_fov(BaseFloat::frac_pi_2());
                        }
                        _ => ()
                    }
                },
                glutin::Event::MouseWheel(glutin::MouseScrollDelta::LineDelta(_, v)) => {
                    let fov = scene.camera.fov();
                    let frac: f32 = (f32::pi() - fov) / f32::pi();
                    let new_fov = f32::max(0., fov + 0.05 * frac * v);
                    scene.camera.set_fov(new_fov);
                },
                glutin::Event::MouseMoved((x, y)) => {
                    if mouse_pressed {
                        let (x, y) = (x as f32, y as f32);
                        let (w, h) = get_display_dim(&ctxt.display);
                        let (w, h) = (w as f32, h as f32);
                        if !RELATIVE_ROTATION {
                            let pitch = (y / h) * f32::two_pi();
                            let yaw = (x / w) * f32::two_pi();
                            scene.camera.set_abs_rotation(pitch, -yaw);
                        } else {
                            if let Some((x_old, y_old)) = old_mouse_coords {
                                let delta_x = x - x_old;
                                let delta_y = y - y_old;

                                let pitch = (delta_y * 0.5 / h) * f32::two_pi();
                                let yaw = (delta_x * 0.5 / w) * f32::two_pi();
                                scene.camera.rotate(pitch, yaw);
                            }
                            old_mouse_coords = Some((x, y));
                        }
                    }
                },
                glutin::Event::MouseInput(state, glutin::MouseButton::Left) => {
                    mouse_pressed = if state == ElementState::Pressed {
                        true
                    } else {
                        old_mouse_coords = None;
                        false
                    };
                },
                glutin::Event::Resized(x, y) => {
                    scene.camera.set_aspect_ratio(x as f32 / y as f32);
                },
                glutin::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<commit_msg>Switched panning from keyboard to mouse<commit_after>#[macro_use]
extern crate glium;
#[macro_use]
extern crate log;

extern crate env_logger;
extern crate image;
extern crate nalgebra;
extern crate obj;
extern crate time;

extern crate genmesh;

mod camera;
mod draw;
mod shader;

use std::collections::HashMap;
use std::io::Read;
use std::fs::File;

use camera::Camera;
use draw::{Cube, Grid, GameObject};
use shader::ShaderType;

use glium::{glutin, Display, DisplayBuild, DrawError, Program, Surface};
use glium::glutin::{ElementState, VirtualKeyCode};

use nalgebra::{zero, BaseFloat, Vec3};

struct Scene {
    objects: Vec<Box<GameObject>>,
    camera: Camera,
}

impl Scene {
    fn new(camera: Camera) -> Self {
        Scene { camera: camera, objects: Vec::new() }
    }

    fn draw(&self, ctxt: &mut EngineContext) {
        let mut target = ctxt.display.draw();
        target.clear_color_and_depth((0., 0., 0., 1.), 1.);
        for obj in self.objects.iter() {
            ctxt.draw(&mut target, &self.camera, obj).unwrap();
        }
        target.finish().unwrap();
    }

    fn add<G: GameObject + 'static>(&mut self, object: G) {
        self.objects.push(Box::new(object));
    }
}

const RELATIVE_ROTATION: bool = true;

fn get_display_dim(display: &Display) -> (u32, u32) {
    match display.get_window().unwrap().get_inner_size() {
        Some(dim) => dim,
        None => panic!("Couldn't get window dimensions")
    }
}

pub struct EngineContext {
    display: Display,
    vertex_shader: String,
    shader_map: HashMap<ShaderType, String>,
}

impl EngineContext {
    pub fn new(display: Display) -> Self {
        let mut shader = String::new();
        File::open("shaders/vertex.glsl").unwrap().read_to_string(&mut shader).unwrap();
        EngineContext { display: display, vertex_shader: shader, shader_map: HashMap::new() }
    }

    pub fn draw<S: Surface>(&mut self, surface: &mut S, camera: &Camera,
                            obj: &Box<GameObject>) -> Result<(), DrawError> {
        let parent = obj.parent();
        let uniforms = obj.construct_uniforms(&camera);

        let &mut EngineContext { ref display, ref vertex_shader, ref mut shader_map } = self;
        let fragment_shader = Self::get_shader(shader_map, parent.shader_type);
        let program = Program::from_source(display, vertex_shader, fragment_shader, None).unwrap();
        surface.draw(&parent.vertex_buffer, parent.indices.clone(), &program, &uniforms,
                     &parent.draw_params)
    }

    fn get_shader(shader_map: &mut HashMap<ShaderType, String>, shader_type: ShaderType) -> &str {
        shader_map.entry(shader_type).or_insert_with(|| {
            let mut shader = String::new();
            File::open(shader_type.to_filename()).unwrap().read_to_string(&mut shader).unwrap();
            shader
        })
    }
}

fn main() {
    env_logger::init().unwrap();

    let display = glutin::WindowBuilder::new()
        .with_dimensions(800, 600)
        .with_title(format!("3D Cube"))
        .build_glium()
        .unwrap();

    let camera = {
        let (w, h) = get_display_dim(&display);
        let (w, h) = (w as f32, h as f32);
        Camera::new(Vec3::new(0., 0., 1.), w / h)
    };

    let mut scene = Scene::new(camera);
    scene.add(Grid::new(&display, 20));
    scene.add(Cube::new(&display, 1., zero()));

    let mut right_mouse_pressed = false;
    let mut left_mouse_pressed = false;
    let mut old_mouse_coords = None;

    let mut ctxt = EngineContext::new(display);
    loop {
        scene.draw(&mut ctxt);

        for ev in ctxt.display.poll_events() {
            match ev {
                glutin::Event::KeyboardInput(ElementState::Pressed, _, Some(key)) => {
                    match key {
                        VirtualKeyCode::R => {
                            scene.camera.set_pos(&Vec3::new(0., 0., 1.));
                            scene.camera.set_abs_rotation(0., 0.);
                            scene.camera.set_fov(BaseFloat::frac_pi_2());
                        }
                        _ => ()
                    }
                },
                glutin::Event::MouseWheel(glutin::MouseScrollDelta::LineDelta(_, v)) => {
                    let fov = scene.camera.fov();
                    let frac: f32 = (f32::pi() - fov) / f32::pi();
                    let new_fov = f32::max(0., fov + 0.05 * frac * v);
                    scene.camera.set_fov(new_fov);
                },
                glutin::Event::MouseMoved((x, y)) => {
                    if right_mouse_pressed {
                        // Rotation
                        let (x, y) = (x as f32, y as f32);
                        let (w, h) = get_display_dim(&ctxt.display);
                        let (w, h) = (w as f32, h as f32);
                        if !RELATIVE_ROTATION {
                            let pitch = (y / h) * f32::two_pi();
                            let yaw = (x / w) * f32::two_pi();
                            scene.camera.set_abs_rotation(pitch, -yaw);
                        } else {
                            if let Some((x_old, y_old)) = old_mouse_coords {
                                let delta_x = x - x_old;
                                let delta_y = y - y_old;

                                let pitch = (delta_y * 0.5 / h) * f32::two_pi();
                                let yaw = (delta_x * 0.5 / w) * f32::two_pi();
                                scene.camera.rotate(pitch, yaw);
                            }
                            old_mouse_coords = Some((x, y));
                        }
                    } else if left_mouse_pressed {
                        // Translation
                        let (x, y) = (x as f32, y as f32);
                        if let Some((x_old, y_old)) = old_mouse_coords {
                            let diff = Vec3::new(x_old - x, y - y_old, 0.) * 0.003 as f32;
                            scene.camera.translate(&diff);
                        }
                        old_mouse_coords = Some((x, y));
                    }
                },
                glutin::Event::MouseInput(state, button) => {
                    if state == ElementState::Released {
                        old_mouse_coords = None;
                    };

                    match button {
                        glutin::MouseButton::Left =>
                            left_mouse_pressed = state == ElementState::Pressed,
                        glutin::MouseButton::Right =>
                            right_mouse_pressed = state == ElementState::Pressed,
                        _ => ()
                    }
                }
                glutin::Event::Resized(x, y) => {
                    scene.camera.set_aspect_ratio(x as f32 / y as f32);
                },
                glutin::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate curl;
extern crate serde_json;

use curl::http;
use serde_json::Value;

pub fn main() {

    let url = "https://www.hautelook.com/api";
    let resp = http::handle()
        .get(url)
        .exec()
        .unwrap_or_else(|e| {
            panic!("Failed to get {}; error is {}", url, e);
        });

    if resp.get_code() != 200 {
        println!("Unable to handle HTTP response code {}", resp.get_code());
        return;
    }

    let body = std::str::from_utf8(resp.get_body()).unwrap_or_else(|e| {
        panic!("Failed to parse response from {}; error is {}", url, e);
    });

    let json: Value = serde_json::from_str(body).unwrap_or_else(|e| {
        panic!("Failed to parse json; error is {}", e);
    });

    let links = json.as_object()
        .and_then(|object| object.get("_links"))
        .and_then(|links| links.as_object())
        .unwrap_or_else(|| {
            panic!("Failed to get '_links' value from json");
        });

    for (rel, link) in links.iter() {
        let href = link.as_object()
            .and_then(|object| object.get("href"))
            .and_then(|value| value.as_string())
            .unwrap_or_else(|| {
                panic!("Failed to get 'href' value from within '_links'");
            });

        println!("{} -> {}", rel, href);
    }
}
<commit_msg>Show example of find<commit_after>extern crate curl;
extern crate serde_json;

use curl::http;
use serde_json::Value;

pub fn main() {

    let url = "https://www.hautelook.com/api";
    let resp = http::handle()
        .get(url)
        .exec()
        .unwrap_or_else(|e| {
            panic!("Failed to get {}; error is {}", url, e);
        });

    if resp.get_code() != 200 {
        println!("Unable to handle HTTP response code {}", resp.get_code());
        return;
    }

    let body = std::str::from_utf8(resp.get_body()).unwrap_or_else(|e| {
        panic!("Failed to parse response from {}; error is {}", url, e);
    });

    let json: Value = serde_json::from_str(body).unwrap_or_else(|e| {
        panic!("Failed to parse json; error is {}", e);
    });

    let links = json.as_object()
        .and_then(|object| object.get("_links"))
        .and_then(|links| links.as_object())
        .unwrap_or_else(|| {
            panic!("Failed to get '_links' value from json");
        });

    for (rel, link) in links.iter() {
        let href = link.find("href")
            .and_then(|value| value.as_string())
            .unwrap_or_else(|| {
                panic!("Failed to get 'href' value from within '_links'");
            });

        println!("{} -> {}", rel, href);
    }
}
<|endoftext|>


<commit_before>extern crate nalgebra as na;
extern crate kiss3d;
extern crate rand;
extern crate num;

use kiss3d::window::Window;
use na::{Pnt2, Pnt3, Norm, FloatPnt, FloatVec};
use rand::{Rng, Closed01};
use num::Zero;

struct SpaceColonization<T, F>
    where T: FloatPnt<f32, F>,
          F: FloatVec<f32> + Zero + Copy
{
    node_parents: Vec<usize>,
    node_positions: Vec<T>,
    leaf_node_pointers: Vec<usize>, // XXX: how can a branch be terminated?
    leaf_node_grow_directions: Vec<F>,
}

impl<T, F> SpaceColonization<T, F>
    where T: FloatPnt<f32, F>,
          F: FloatVec<f32> + Zero + Copy
{
    fn new() -> SpaceColonization<T, F> {
        SpaceColonization {
            node_parents: Vec::new(),
            node_positions: Vec::new(),
            leaf_node_pointers: Vec::new(),
            leaf_node_grow_directions: Vec::new(),
        }
    }

    // adds initial root node(s)
    fn add_root_node(&mut self, pos: T) {
        debug_assert!(self.node_positions.len() == self.node_parents.len()); // invariant
        debug_assert!(self.leaf_node_pointers.len() == self.leaf_node_grow_directions.len()); // invariant

        let idx = self.node_positions.len();
        self.node_positions.push(pos);

        // a root node has it's own index as parent
        self.node_parents.push(idx);

        // a root node creates a new "leaf" node (better: branch!)
        self.leaf_node_pointers.push(idx);
        self.leaf_node_grow_directions.push(Zero::zero());

        debug_assert!(self.node_positions.len() == self.node_parents.len()); // invariant
        debug_assert!(self.leaf_node_pointers.len() == self.leaf_node_grow_directions.len()); // invariant
    }

    fn add_moved_leaf_node(&mut self, leaf_node_slot: usize, v: F) {
        let parent = self.leaf_node_pointers[leaf_node_slot];
        let parent_pos = self.node_positions[parent];

        self.update_leaf_node(leaf_node_slot, parent_pos + v)
    }

    fn update_leaf_node(&mut self, leaf_node_slot: usize, new_pos: T) {
        let parent = self.leaf_node_pointers[leaf_node_slot];

        // create new node
        let idx = self.node_positions.len();
        self.node_positions.push(new_pos);
        self.node_parents.push(parent);

        // update the leaf node pointer
        self.leaf_node_pointers[leaf_node_slot] = idx;
    }

    fn find_nearest_leaf_for_attraction_point(&self,
                                              attraction_pt: &T,
                                              radius_influence_sq: f32)
                                              -> Option<(usize, f32)> {
        let mut nearest_leaf: Option<usize> = None;
        let mut nearest_distance_sq: f32 = radius_influence_sq;

        for (i, &leaf_node_ptr) in self.leaf_node_pointers.iter().enumerate() {
            let leaf_pos = &self.node_positions[leaf_node_ptr];
            let dist_sq = leaf_pos.sqdist(attraction_pt);

            // is the attraction point within the radius of influence
            // and closed than the currently best
            if dist_sq < nearest_distance_sq {
                nearest_distance_sq = dist_sq;
                nearest_leaf = Some(i);
            }
        }

        return nearest_leaf.map(|idx| (idx, nearest_distance_sq));
    }

    fn iter_segments<C>(&self, callback: &mut C)
        where C: FnMut(&T, &T)
    {
        for (i, &parent) in self.node_parents.iter().enumerate() {
            if i != parent {
                callback(&self.node_positions[i], &self.node_positions[parent]);
            }
        }
    }

    fn iterate(&mut self,
               attraction_points: &mut [(T, bool)],
               radius_influce_sq: f32,
               move_distance: f32,
               kill_distance_sq: f32) {
        // reset all attraction forces
        for force in &mut self.leaf_node_grow_directions {
            *force = Zero::zero();
        }

        // for each attraction_point, find the nearest (leaf) node that it
        // influences.
        for ap in attraction_points.iter_mut() {
            let active = ap.1;
            if !active {
                continue;
            }
            let nearest_leaf_opt = self.find_nearest_leaf_for_attraction_point(&ap.0,
                                                                               radius_influce_sq);
            if let Some((nearest_leaf_slot, d_sq)) = nearest_leaf_opt {
                let nearest_leaf_node_idx = self.leaf_node_pointers[nearest_leaf_slot];
                // update the force with the normalized vector towards the attraction point
                let v = (ap.0 - self.node_positions[nearest_leaf_node_idx]).normalize();
                self.leaf_node_grow_directions[nearest_leaf_slot] =
                    self.leaf_node_grow_directions[nearest_leaf_slot] + v;

                if d_sq < kill_distance_sq {
                    // set inactive
                    ap.1 = false;
                }
            }
        }

        // now create new leaf nodes
        for i in 0..self.leaf_node_grow_directions.len() {
            let force = self.leaf_node_grow_directions[i];

            // update leaf node only if there is a force!
            if !force.is_zero() {
                let n = force.normalize();
                self.add_moved_leaf_node(i, n * move_distance);
            }
        }

    }
}

fn random_coord<R: Rng>(rng: &mut R) -> f32 {
    2.0 * rng.gen::<Closed01<f32>>().0 - 1.0
}

fn random_point<R: Rng>(rng: &mut R) -> Pnt2<f32> {
    Pnt2::new(random_coord(rng), random_coord(rng))
}

const Z: f32 = 3.0;

fn main() {
    let mut rng = rand::thread_rng();

    let n_attraction_points = 5000;

    // generate initial attraction point configuration
    // stores status of attraction point in the second tuple element (true=active, false=used)
    let mut attraction_points: Vec<_> = (0..n_attraction_points)
                                            .into_iter()
                                            .map(|_| (random_point(&mut rng), true))
                                            .collect();

    let mut sc = SpaceColonization::new();
    sc.add_root_node(random_point(&mut rng));
    sc.add_root_node(random_point(&mut rng));
    sc.add_root_node(random_point(&mut rng));

    let mut window = Window::new("Space Colonization");
    let white = Pnt3::new(1.0, 1.0, 1.0);

    let mut i = 0;

    while window.render() {
        i += 1;
        println!("Iteration: {}", i);
        for &(ref pt, status) in &attraction_points {
            if status {
                window.draw_point(&Pnt3::new(pt.x, pt.y, Z), &white);
            }
        }

        sc.iter_segments(&mut |a, b| {
            window.draw_line(&Pnt3::new(a.x, a.y, Z), &Pnt3::new(b.x, b.y, Z), &white);
        });

        sc.iterate(&mut attraction_points, 0.1 * 0.1, 0.01, 0.005);
    }
}
<commit_msg>Move configuration out<commit_after>extern crate nalgebra as na;
extern crate kiss3d;
extern crate rand;
extern crate num;

use kiss3d::window::Window;
use na::{Pnt2, Pnt3, Vec2, Vec3, Norm, FloatPnt, FloatVec};
use rand::{Rng, Closed01};
use num::Zero;

struct SpaceColonization<T, F>
    where T: FloatPnt<f32, F>,
          F: FloatVec<f32> + Zero + Copy
{
    node_parents: Vec<usize>,
    node_positions: Vec<T>,
    leaf_node_pointers: Vec<usize>, // XXX: how can a branch be terminated?
    leaf_node_grow_directions: Vec<F>,
}

impl<T, F> SpaceColonization<T, F>
    where T: FloatPnt<f32, F>,
          F: FloatVec<f32> + Zero + Copy
{
    fn new() -> SpaceColonization<T, F> {
        SpaceColonization {
            node_parents: Vec::new(),
            node_positions: Vec::new(),
            leaf_node_pointers: Vec::new(),
            leaf_node_grow_directions: Vec::new(),
        }
    }

    // adds initial root node(s)
    fn add_root_node(&mut self, pos: T) {
        debug_assert!(self.node_positions.len() == self.node_parents.len()); // invariant
        debug_assert!(self.leaf_node_pointers.len() == self.leaf_node_grow_directions.len()); // invariant

        let idx = self.node_positions.len();
        self.node_positions.push(pos);

        // a root node has it's own index as parent
        self.node_parents.push(idx);

        // a root node creates a new "leaf" node (better: branch!)
        self.leaf_node_pointers.push(idx);
        self.leaf_node_grow_directions.push(Zero::zero());

        debug_assert!(self.node_positions.len() == self.node_parents.len()); // invariant
        debug_assert!(self.leaf_node_pointers.len() == self.leaf_node_grow_directions.len()); // invariant
    }

    fn add_moved_leaf_node(&mut self, leaf_node_slot: usize, v: F) {
        let parent = self.leaf_node_pointers[leaf_node_slot];
        let parent_pos = self.node_positions[parent];

        self.update_leaf_node(leaf_node_slot, parent_pos + v)
    }

    fn update_leaf_node(&mut self, leaf_node_slot: usize, new_pos: T) {
        let parent = self.leaf_node_pointers[leaf_node_slot];

        // create new node
        let idx = self.node_positions.len();
        self.node_positions.push(new_pos);
        self.node_parents.push(parent);

        // update the leaf node pointer
        self.leaf_node_pointers[leaf_node_slot] = idx;
    }

    fn find_nearest_leaf_for_attraction_point(&self,
                                              attraction_pt: &T,
                                              radius_influence_sq: f32)
                                              -> Option<(usize, f32)> {
        let mut nearest_leaf: Option<usize> = None;
        let mut nearest_distance_sq: f32 = radius_influence_sq;

        for (i, &leaf_node_ptr) in self.leaf_node_pointers.iter().enumerate() {
            let leaf_pos = &self.node_positions[leaf_node_ptr];
            let dist_sq = leaf_pos.sqdist(attraction_pt);

            // is the attraction point within the radius of influence
            // and closed than the currently best
            if dist_sq < nearest_distance_sq {
                nearest_distance_sq = dist_sq;
                nearest_leaf = Some(i);
            }
        }

        return nearest_leaf.map(|idx| (idx, nearest_distance_sq));
    }

    fn iter_segments<C>(&self, callback: &mut C)
        where C: FnMut(&T, &T)
    {
        for (i, &parent) in self.node_parents.iter().enumerate() {
            if i != parent {
                callback(&self.node_positions[i], &self.node_positions[parent]);
            }
        }
    }

    fn iterate(&mut self,
               attraction_points: &mut [(T, bool)],
               radius_influce_sq: f32,
               move_distance: f32,
               kill_distance_sq: f32) {
        // reset all attraction forces
        for force in &mut self.leaf_node_grow_directions {
            *force = Zero::zero();
        }

        // for each attraction_point, find the nearest (leaf) node that it
        // influences.
        for ap in attraction_points.iter_mut() {
            let active = ap.1;
            if !active {
                continue;
            }
            let nearest_leaf_opt = self.find_nearest_leaf_for_attraction_point(&ap.0,
                                                                               radius_influce_sq);
            if let Some((nearest_leaf_slot, d_sq)) = nearest_leaf_opt {
                let nearest_leaf_node_idx = self.leaf_node_pointers[nearest_leaf_slot];
                // update the force with the normalized vector towards the attraction point
                let v = (ap.0 - self.node_positions[nearest_leaf_node_idx]).normalize();
                self.leaf_node_grow_directions[nearest_leaf_slot] =
                    self.leaf_node_grow_directions[nearest_leaf_slot] + v;

                if d_sq < kill_distance_sq {
                    // set inactive
                    ap.1 = false;
                }
            }
        }

        // now create new leaf nodes
        for i in 0..self.leaf_node_grow_directions.len() {
            let force = self.leaf_node_grow_directions[i];

            // update leaf node only if there is a force!
            if !force.is_zero() {
                let n = force.normalize();
                self.add_moved_leaf_node(i, n * move_distance);
            }
        }

    }
}

const Z_OFF: f32 = 0.0;

fn random_closed01<R: Rng>(rng: &mut R) -> f32 {
    rng.gen::<Closed01<f32>>().0
}

fn random_coord<R: Rng>(rng: &mut R) -> f32 {
    2.0 * random_closed01(rng) - 1.0
}

trait MyPoint {
    fn into_pnt3(self) -> Pnt3<f32>;
    fn random<R: Rng>(rng: &mut R) -> Self;
}

impl MyPoint for Pnt3<f32> {
    fn into_pnt3(self) -> Pnt3<f32> {
        self
    }

    fn random<R: Rng>(rng: &mut R) -> Pnt3<f32> {
        Pnt3::new(random_coord(rng),
                  random_coord(rng),
                  random_coord(rng) + Z_OFF)
    }
}

impl MyPoint for Pnt2<f32> {
    fn into_pnt3(self) -> Pnt3<f32> {
        Pnt3::new(self.x, self.y, 3.0)
    }

    fn random<R: Rng>(rng: &mut R) -> Pnt2<f32> {
        Pnt2::new(random_coord(rng), random_coord(rng))
    }
}

struct Config {
    n_attraction_points: usize,
    n_roots: usize,
    influence_radius: f32,
    move_distance: f32,
    kill_distance: f32,
}

fn run<T, F>(config: &Config)
    where T: MyPoint + FloatPnt<f32, F>,
          F: FloatVec<f32> + Zero + Copy
{
    let mut rng = rand::thread_rng();

    // generate initial attraction point configuration
    // stores status of attraction point in the second tuple element (true=active, false=used)
    let mut attraction_points: Vec<(T, bool)> = (0..config.n_attraction_points)
                                                    .into_iter()
                                                    .map(|_| {
                                                        (<T as MyPoint>::random(&mut rng), true)
                                                    })
                                                    .collect();

    let mut sc: SpaceColonization<T, F> = SpaceColonization::new();
    for _ in 0..config.n_roots {
        sc.add_root_node(<T as MyPoint>::random(&mut rng));
    }

    let mut window = Window::new("Space Colonization");
    let white = Pnt3::new(1.0, 1.0, 1.0);

    let mut i = 0;

    while window.render() {
        i += 1;
        println!("Iteration: {}", i);
        for &(pt, status) in &attraction_points {
            if status {
                window.draw_point(&pt.into_pnt3(), &white);
            }
        }

        sc.iter_segments(&mut |&a, &b| {
            window.draw_line(&a.into_pnt3(), &b.into_pnt3(), &white);
        });

        sc.iterate(&mut attraction_points,
                   config.influence_radius * config.influence_radius,
                   config.move_distance,
                   config.kill_distance * config.kill_distance);
    }
}

fn main() {
    let use_2d = false;
    let config = Config {
        n_attraction_points: 10_000,
        n_roots: 5,
        influence_radius: 0.44, // 0.1
        kill_distance: 0.22, // 0.07
        move_distance: 0.02, // 0.01
    };

    if use_2d {
        run::<Pnt2<f32>, Vec2<f32>>(&config);
    } else {
        run::<Pnt3<f32>, Vec3<f32>>(&config);
    }
}
<|endoftext|>


<commit_before>#![allow(unused_must_use)]
use std::fs;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use std::vec::Vec;
use std::env;

const INVALIDS: &'static [&'static str] = &[".", "/", "-", "::", ">", "<", " "];

pub fn asset_name_by_filepath(path: &Path) -> String {
    let mut strpath = path.to_str().unwrap().to_string();

    for invalid in INVALIDS {
        strpath = strpath.replace(invalid, "_");
    }
    strpath
}

fn recursive_read(list: &mut Vec<u8>, pp: &mut Vec<u8>, buffer: &mut Vec<u8>, filepath: &Path) {
    match fs::read_dir(filepath) {
        Err(why) => panic!("Directory {} {:?}", filepath.display(), why.kind()),
        Ok(paths) => for entry in paths {
            let path = entry.unwrap().path();
            println!("Reading -> {:?}", path.display());
            if fs::metadata(&path).unwrap().is_dir() {
                recursive_read(list, pp, buffer, &path);
            } else {
                let mut file = File::open(&path).unwrap_or_else(|e| {
                    panic!("couldn't open file {}: {}", e, filepath.display());
                });
                let mut text: Vec<u8> = vec![];
                file.read_to_end(&mut text).unwrap_or_else(|e| {
                    panic!("couldn't read file {}: {}", e, filepath.display());
                });;
                let asset_name = asset_name_by_filepath(&path);
                write!(list, "    \"");
                write!(list, "{}", path.display());
                write!(list, "\",\n");
                write!(pp, "    \"");
                write!(pp, "{}", path.display());
                write!(pp, "\"");
                write!(pp, " => Result::Ok(&");
                write!(pp, "{}", asset_name);
                write!(pp, "),\n");
                write!(buffer, "pub static ");
                write!(buffer, "{}", asset_name);
                write!(buffer, ": [u8; ");
                write!(buffer, "{}", &text.len().to_string());
                write!(buffer, "] = ");
                write!(buffer, "{:?}", text);
                write!(buffer, ";\n");
            }
        },
    }
}

fn print_usage() {
    print!("
rust-embed v0.2.0
Generates rust code to embed resource files into your library or executable

  Usage:
    rust-embed input_folder output_file

  where:
    input_folder  string is the path to the folder containing the assets.
    output_file   string is output filename.

  example:
    rust-embed ./src/public ./src/assets.rs
");
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() <= 2 {
        print_usage();
        return;
    }
    let ref input_folder = args[1];
    let ref output_file = args[2];

    // Recursive read section buffers
    let mut output_buffer: Vec<u8> = vec![];
    let mut pp: Vec<u8> = vec![];
    let mut list: Vec<u8> = vec![];

    write!(output_buffer, "#![allow(dead_code)]");
    write!(output_buffer, "#![allow(non_upper_case_globals)]\n");
    write!(list, "{}", "\npub fn list() -> Vec<&'static str> {\n  vec![\n");
    write!(pp, "{}", "\npub fn get(name: &str) -> Result<&[u8], &str> {\n  match name {\n");
    recursive_read(&mut list, &mut pp, &mut output_buffer, Path::new(input_folder));
    write!(list, "{}", "]}");
    write!(pp, "    _=> Result::Err(\"File Not Found\")\n");
    write!(pp, "{}", "  }\n}\n");
    let op = Path::new(output_file);
    println!("Writing -> {:?}", pp);
    println!("Writing -> {:?}", list);
    println!("Writing -> {:?}", op.display());
    let mut file = File::create(&op).unwrap_or_else(|e| {
        panic!("couldn't create {} {:?}", op.display(), e)
    });
    file.write_all(&output_buffer).unwrap_or_else(|e| {
        panic!("couldn't write to {} {:?}", op.display(), e);
    });
    file.write_all(&pp).unwrap_or_else(|e| {
        panic!("couldn't write to {} {:?}", op.display(), e);
    });
    file.write_all(&list).unwrap_or_else(|e| {
        panic!("couldn't write to {} {:?}", op.display(), e);
    });
}
<commit_msg>Add #![allow(clippy)] to generated file<commit_after>#![allow(unused_must_use)]
use std::fs;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use std::vec::Vec;
use std::env;

const INVALIDS: &'static [&'static str] = &[".", "/", "-", "::", ">", "<", " "];

pub fn asset_name_by_filepath(path: &Path) -> String {
    let mut strpath = path.to_str().unwrap().to_string();

    for invalid in INVALIDS {
        strpath = strpath.replace(invalid, "_");
    }
    strpath
}

fn recursive_read(list: &mut Vec<u8>, pp: &mut Vec<u8>, buffer: &mut Vec<u8>, filepath: &Path) {
    match fs::read_dir(filepath) {
        Err(why) => panic!("Directory {} {:?}", filepath.display(), why.kind()),
        Ok(paths) => for entry in paths {
            let path = entry.unwrap().path();
            println!("Reading -> {:?}", path.display());
            if fs::metadata(&path).unwrap().is_dir() {
                recursive_read(list, pp, buffer, &path);
            } else {
                let mut file = File::open(&path).unwrap_or_else(|e| {
                    panic!("couldn't open file {}: {}", e, filepath.display());
                });
                let mut text: Vec<u8> = vec![];
                file.read_to_end(&mut text).unwrap_or_else(|e| {
                    panic!("couldn't read file {}: {}", e, filepath.display());
                });;
                let asset_name = asset_name_by_filepath(&path);
                write!(list, "    \"");
                write!(list, "{}", path.display());
                write!(list, "\",\n");
                write!(pp, "    \"");
                write!(pp, "{}", path.display());
                write!(pp, "\"");
                write!(pp, " => Result::Ok(&");
                write!(pp, "{}", asset_name);
                write!(pp, "),\n");
                write!(buffer, "pub static ");
                write!(buffer, "{}", asset_name);
                write!(buffer, ": [u8; ");
                write!(buffer, "{}", &text.len().to_string());
                write!(buffer, "] = ");
                write!(buffer, "{:?}", text);
                write!(buffer, ";\n");
            }
        },
    }
}

fn print_usage() {
    print!("
rust-embed v0.2.0
Generates rust code to embed resource files into your library or executable

  Usage:
    rust-embed input_folder output_file

  where:
    input_folder  string is the path to the folder containing the assets.
    output_file   string is output filename.

  example:
    rust-embed ./src/public ./src/assets.rs
");
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() <= 2 {
        print_usage();
        return;
    }
    let ref input_folder = args[1];
    let ref output_file = args[2];

    // Recursive read section buffers
    let mut output_buffer: Vec<u8> = vec![];
    let mut pp: Vec<u8> = vec![];
    let mut list: Vec<u8> = vec![];

    write!(output_buffer, "#![allow(dead_code)]");
    write!(output_buffer, "#![allow(non_upper_case_globals)]");
    write!(output_buffer, "#![allow(clippy)]\n");
    write!(list, "{}", "\npub fn list() -> Vec<&'static str> {\n  vec![\n");
    write!(pp, "{}", "\npub fn get(name: &str) -> Result<&[u8], &str> {\n  match name {\n");
    recursive_read(&mut list, &mut pp, &mut output_buffer, Path::new(input_folder));
    write!(list, "{}", "]}");
    write!(pp, "    _=> Result::Err(\"File Not Found\")\n");
    write!(pp, "{}", "  }\n}\n");
    let op = Path::new(output_file);
    println!("Writing -> {:?}", pp);
    println!("Writing -> {:?}", list);
    println!("Writing -> {:?}", op.display());
    let mut file = File::create(&op).unwrap_or_else(|e| {
        panic!("couldn't create {} {:?}", op.display(), e)
    });
    file.write_all(&output_buffer).unwrap_or_else(|e| {
        panic!("couldn't write to {} {:?}", op.display(), e);
    });
    file.write_all(&pp).unwrap_or_else(|e| {
        panic!("couldn't write to {} {:?}", op.display(), e);
    });
    file.write_all(&list).unwrap_or_else(|e| {
        panic!("couldn't write to {} {:?}", op.display(), e);
    });
}
<|endoftext|>