<commit_before>extern crate regex;
extern crate irc;
extern crate xdg_basedir;
extern crate hyper;
extern crate url;

mod github;

use regex::Regex;
use irc::client::prelude::*;
use xdg_basedir::*;
use std::io::Read;
use std::vec::Vec;
use std::iter::FromIterator;
use url::Url;

fn parse_post(post: &str) -> Option<String> {
    let client = hyper::client::Client::new();
    let urlregex = Regex::new(r"https?://\S+\.[:alpha:]{2,}\S+").unwrap();

    if let Some(x) = urlregex.captures(post) {
        if let Ok(parsedurl) = Url::parse(x.at(0).unwrap()) {
            if parsedurl.domain().unwrap().ends_with("github.com") {
                let urlpath = Vec::from_iter(parsedurl.path_segments().unwrap());
                if urlpath.len() == 4 &&
                    (urlpath[2] == "issues" || urlpath[2] == "pull") {
                        return github::get_display_text(&urlpath[0],
                                                        &urlpath[1],
                                                        &urlpath[3],
                                                        false).ok();
                    }
            }
        }
        if let Ok(mut resp) = client.get(x.at(0).unwrap()).send() {
            let mut body = String::new();
            if let Err(..) = resp.read_to_string(&mut body) {
                return None; // Not UTF8 (binary file?)
            }
            let titleregex = Regex::new(r"<title>(.+)</title>").unwrap();
            if let Some(cap) = titleregex.captures(&body) {
                return Some(format!("Title: {}", cap.at(1).unwrap()));
            }
        }
    }

    let issueregex = Regex::new(r"([^ ()]+)/([^ ()]+)#(\d+)").unwrap();

    if let Some(cap) = issueregex.captures(post) {
        let user = cap.at(1).unwrap();
        let repo = cap.at(2).unwrap();
        let number = cap.at(3).unwrap();
        return github::get_display_text(user, repo, number, true).ok();
    }
    None
}

fn handle_message(server: &IrcServer, from: &str, to: &str, message: &str) {
    let nickname = server.config().nickname.as_ref().unwrap();

    if to == nickname && from == "ids1024" {
        let mut words = message.split_whitespace();
        let command = words.next().unwrap_or("");
        let parameter = words.next().unwrap_or("");
        match command {
            "join" => server.send_join(parameter).unwrap(),
            "part" => server.send(
                Command::PART(parameter.to_string(), None)
                ).unwrap(),
            "quit" => server.send_quit("").unwrap(),
            _ => {},
        }
    }

    if let Some(x) = parse_post(&message) {
        for line in x.lines() {
            server.send_notice(&to, &line).unwrap();
        }
    }
}

fn main() {
    let mut configpath = get_config_home().unwrap();
    configpath.push("idsbot/config.json");

    let config = Config::load(configpath).unwrap();
    let server = IrcServer::from_config(config).unwrap();
    server.identify().unwrap();

    for message in server.iter() {
        let message = message.unwrap();
        print!("{}", message.to_string());
        let from = message.source_nickname().map(|s| s.to_owned());
        if let Command::PRIVMSG(to, content) = message.command {
            handle_message(&server, &from.unwrap(), &to, &content);
        }
    }
}
<commit_msg>Use else if<commit_after>extern crate regex;
extern crate irc;
extern crate xdg_basedir;
extern crate hyper;
extern crate url;

mod github;

use regex::Regex;
use irc::client::prelude::*;
use xdg_basedir::*;
use std::io::Read;
use std::vec::Vec;
use std::iter::FromIterator;
use url::Url;

fn parse_post(post: &str) -> Option<String> {
    let client = hyper::client::Client::new();
    let urlregex = Regex::new(r"https?://\S+\.[:alpha:]{2,}\S+").unwrap();
    let issueregex = Regex::new(r"([^ ()]+)/([^ ()]+)#(\d+)").unwrap();

    if let Some(x) = urlregex.captures(post) {
        if let Ok(parsedurl) = Url::parse(x.at(0).unwrap()) {
            if parsedurl.domain().unwrap().ends_with("github.com") {
                let urlpath = Vec::from_iter(parsedurl.path_segments().unwrap());
                if urlpath.len() == 4 &&
                    (urlpath[2] == "issues" || urlpath[2] == "pull") {
                        return github::get_display_text(&urlpath[0],
                                                        &urlpath[1],
                                                        &urlpath[3],
                                                        false).ok();
                    }
            }
        }
        if let Ok(mut resp) = client.get(x.at(0).unwrap()).send() {
            let mut body = String::new();
            if let Err(..) = resp.read_to_string(&mut body) {
                return None; // Not UTF8 (binary file?)
            }
            let titleregex = Regex::new(r"<title>(.+)</title>").unwrap();
            if let Some(cap) = titleregex.captures(&body) {
                return Some(format!("Title: {}", cap.at(1).unwrap()));
            }
        }
    } else if let Some(cap) = issueregex.captures(post) {
        let user = cap.at(1).unwrap();
        let repo = cap.at(2).unwrap();
        let number = cap.at(3).unwrap();
        return github::get_display_text(user, repo, number, true).ok();
    }
    None
}

fn handle_message(server: &IrcServer, from: &str, to: &str, message: &str) {
    let nickname = server.config().nickname.as_ref().unwrap();

    if to == nickname && from == "ids1024" {
        let mut words = message.split_whitespace();
        let command = words.next().unwrap_or("");
        let parameter = words.next().unwrap_or("");
        match command {
            "join" => server.send_join(parameter).unwrap(),
            "part" => server.send(
                Command::PART(parameter.to_string(), None)
                ).unwrap(),
            "quit" => server.send_quit("").unwrap(),
            _ => {},
        }
    }

    if let Some(x) = parse_post(&message) {
        for line in x.lines() {
            server.send_notice(&to, &line).unwrap();
        }
    }
}

fn main() {
    let mut configpath = get_config_home().unwrap();
    configpath.push("idsbot/config.json");

    let config = Config::load(configpath).unwrap();
    let server = IrcServer::from_config(config).unwrap();
    server.identify().unwrap();

    for message in server.iter() {
        let message = message.unwrap();
        print!("{}", message.to_string());
        let from = message.source_nickname().map(|s| s.to_owned());
        if let Command::PRIVMSG(to, content) = message.command {
            handle_message(&server, &from.unwrap(), &to, &content);
        }
    }
}
<|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;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate serde_derive;
use lapp;
use shlex;

use es::traits::*;
use std::process;
use std::env;
use std::fs;
use std::path::{Path,PathBuf};
use std::collections::{HashSet};
use std::env::consts::EXE_SUFFIX;

mod crate_utils;
mod platform;
mod strutil;
mod meta;
mod cargo_lock;
mod cache;
mod state;
mod compile;

use platform::{open,edit};
use crate_utils::RUSTUP_LIB;
use state::State;
use compile::{compile_crate,massage_snippet};

const VERSION: &str = "0.4.0";

const USAGE: &str = "
Compile and run small Rust snippets
  -s, --static build statically (default is dynamic)
  -d, --dynamic overrides --static in env.rs
  -O, --optimize optimized static build
  -e, --expression evaluate an expression
  -i, --iterator iterate over an expression
  -n, --lines evaluate expression over stdin; the var 'line' is defined
  -x, --extern... (string) add an extern crate to the snippet
  -X, --wild... (string) like -x but implies wildcard import
  -M, --macro... (string) like -x but implies macro import
  -p, --prepend (default '') put this statement in body (useful for -i etc)
  -N, --no-prelude do not include runner prelude
  -c, --compile-only  will not run program and copies it into ~/.cargo/bin
  -r, --run  don't compile, only re-run
  -S, --no-simplify by default, attempt to simplify rustc error messages
  -E, --edition (default '2015') Rust edition

  Cache Management:
  --add  (string...) add new crates to the cache
  --update update all, or a specific package given as argument
  --edit  edit the static cache Cargo.toml
  --build rebuild the static cache
  --cleanup clean out stale rlibs from cache
  --crates current crates and their versions in cache
  --doc  display documentation (any argument will be specific crate name)
  --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)
  -L, --link (string) path for extra libraries
  --cfg... (string) pass configuration variables to rustc
  --features (string...) enable features in compilation
  --libc  link dynamically against libc (special case)
  (--extern is used to explicitly link in a crate by name)

  -v, --verbose describe what's happening
  -V, --version version of runner

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

fn main() {
    let mut args = lapp::Args::new(USAGE);
    args.parse_spec().or_die("bad spec");
    let env = Path::new("env.rs");
    let env_prelude = if env.exists() {
        let contents = fs::read_to_string(env).or_die("cannot read env.rs");
        {
            let first_line = contents.lines().next().or_die("empty env.rs");
            let arg_comment = "//ARGS ";
            if first_line.starts_with(arg_comment) {
                let default_args = &first_line[arg_comment.len()..];
                let default_args = shlex::split(default_args).or_die("bad default args");
                args.parse_command_line(default_args).or_die("cannot parse default args");
                args.clear_used();
            }
        }
        Some(contents)
    } else {
        None
    };

    args.parse_env_args().or_die("bad command line");

    let mut prelude = cache::get_prelude();
    if let Some(env_prelude) = env_prelude {
        prelude.insert_str(0, &env_prelude);
    }
    let b = |p| args.get_bool(p);

    let exe_suffix = if EXE_SUFFIX.len() > 0 {
        &EXE_SUFFIX[1..]
    } else {
        ""
    };

    if b("version") {
        println!("runner {}",VERSION);
        return;
    }
    let verbose = b("verbose");

    if b("run") && b("compile-only") {
        args.quit("--run and compile-only make no sense together");
    }

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

    if b("edit-prelude") {
        let rdir = cache::runner_directory().join("prelude");
        edit(&rdir);
        return;
    }

    // Static Cache Management
    let crates = args.get_strings("add");
    if crates.len() > 0 {
        cache::create_static_cache(&crates);
        return;
    }

    // operations on the static cache
    let (edit_toml, build, doc, update, cleanup, crates) =
        (b("edit"), b("build"), b("doc"), b("update"), b("cleanup"), b("crates"));

    if edit_toml || build || doc || update || cleanup || crates {
        let maybe_argument = args.get_string_result("program");
        let static_cache = cache::static_cache_dir_check();
        if build || update {
            env::set_current_dir(&static_cache).or_die("static cache wasn't a directory?");
            if build {
                cache::build_static_cache();
            } else {
                if let Ok(package) = maybe_argument {
                    cache::cargo(&["update","--package",&package]);
                } else {
                    cache::cargo(&["update"]);
                }
                return;
            }
        } else
        if doc {
            let the_crate = crate_utils::proper_crate_name(
                &if let Ok(file) =  maybe_argument {
                    file
                } else {
                    "static_cache".to_string()
                }
            );
            let docs = static_cache.join(&format!("target/doc/{}/index.html",the_crate));
            open(&docs);
        } else
        if cleanup {
            cache::cargo(&["clean"]);
        } else
        if crates {
            let mut m = cache::get_metadata();
            let mut crates = Vec::new();
            if let Some(name) = maybe_argument.ok() {
                crates.push(name);
                crates.extend(args.get_strings("args"));
            }
            m.dump_crates(crates, verbose);
        } else { // must be edit_toml
            let toml = static_cache.join("Cargo.toml");
            edit(&toml);
        }
        return;
    }

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

    // Dynamically linking crates (experimental!)
    let (print_path, compile) = (b("crate-path"),b("compile"));
    if print_path || compile {
        let state = State::dll(optimized, &edition);
        // plain-jane name is a crate name!
        if crate_utils::plain_name(&first_arg) {
            // but is it one of Ours? Then we definitely know what the
            // actual crate name is AND where the source is cached
            let m = cache::get_metadata();
            if let Some(e) = m.get_meta_entry(&first_arg) {
                if e.path == Path::new("") {
                    args.quit("please run 'runner --build' to update metadata");
                }
                if print_path {
                   // will be <cargo dir>/src/FILE.rs
                    let path = e.path.parent().unwrap().parent().unwrap();
                    println!("{}",path.display());
                } else {
                    // TBD can override --features with features actually
                    // used to build this crate
                    let build_features = &e.features;
                    println!("building crate '{}' {} at {}",e.crate_name, build_features, e.path.display());
                    compile_crate(&args, &state, &e.crate_name, &e.path, None,
                        Vec::new(),
                        build_features.split_whitespace().map(|s| s.to_string()).collect()
                    );
                }
                return;
            }
        } else
        if compile { // either a cargo directory or a Rust source file
            if ! file.exists() {
                args.quit("no such file or directory");
            }
            let (crate_name, crate_path) = if file.is_dir() {
                match crate_utils::cargo_dir(&file) {
                    Ok((path,cargo_toml)) => {
                        // this is somewhat dodgy, since the default location can be changed
                        // Safest bet is to add the crate to the runner static cache
                        let source = path.join("src").join("lib.rs");
                        let name = crate_utils::crate_name(&cargo_toml);
                        (name, source)
                    },
                    Err(msg) => args.quit(&msg)
                }
            } 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(""));
                (name, file.clone())
            };
            println!("building crate '{}' at {}",crate_name, crate_path.display());
            compile_crate(&args, &state, &crate_name, &crate_path, None,  Vec::new(),Vec::new());
            return;
        } else { // we no longer go for wild goose chase to find crates in the Cargo cache
            args.quit("not found in the static cache");
        }
    }

    let static_state = b("static") && ! b("dynamic");
    let state = State::exe(static_state,optimized, &edition);

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

    let mut expression = true;
    use cache::quote;
    let mut code = if b("expression") {
        // Evaluating an expression: just debug print it out.
        format!("println!(\"{{:?}}\",{});", quote(first_arg))
    } else
    if b("iterator") {
        // The expression is anything that implements IntoIterator
        format!("for val in {} {{\n println!(\"{{:?}}\",val);\n}}", quote(first_arg))
    } else
    if b("lines") {
        // The variable 'line' is available to an expression, evaluated for each line in stdin
        // But if the expression ends with '}' then don't dump out this value!
        let first_arg = quote(first_arg);
        let stmt = first_arg.trim_end().ends_with('}');
        let mut s = String::from("
            let stdin = io::stdin();
            for line in stdin.lock().lines() {
                let line = line?;
        ");
        s += &if ! stmt {
            format!("let val = {};\nprintln!(\"{{:?}}\",val);", first_arg)
        } else {
            format!("  {};",first_arg)
        };
        s += "\n}";
        s
    } else { // otherwise, just a file
        expression = false;
        fs::read_to_string(&file).or_die("cannot read file")
    };

    // ALL executables go into the Runner bin directory...
    let mut bin = cache::runner_directory().join("bin");
    let mut externs = Vec::new();

    // proper Rust programs are accepted (this is a bit rough)
    let proper = code.find("fn main").is_some();
    let (rust_file, program) = if ! proper {
        // otherwise we must create a proper program from the snippet
        // and write this as a file in the Runner bin directory...
        let mut extern_crates = args.get_strings("extern");
        let wild_crates = args.get_strings("wild");
        let macro_crates = args.get_strings("macro");
        if wild_crates.len() > 0 {
            extern_crates.extend(wild_crates.iter().cloned());
        }
        if macro_crates.len() > 0 {
            extern_crates.extend(macro_crates.iter().cloned());
        }
        let macro_crates: HashSet<_> = macro_crates.into_iter().collect();

        let mut extra = args.get_string("prepend");
        if ! extra.is_empty() {
            extra.push(';');
        }
        let maybe_prelude = if b("no-prelude") {
            "".into()
        } else {
            prelude
        };

        let (massaged_code, deduced_externs)
            = massage_snippet(code, maybe_prelude, extern_crates, wild_crates, macro_crates, extra);
        code = massaged_code;
        externs = deduced_externs;
        if ! expression {
            bin.push(&file);
            bin.set_extension("rs");
        } else { // we make up a name...
            bin.push("tmp.rs");
        }
        fs::write(&bin,&code).or_die("cannot write code");
        let program = bin.with_extension(exe_suffix);
        (bin, program)
    } else {
        for line in code.lines() {
            if let Some(crate_name) = strutil::word_after(line,"extern crate ") {
                externs.push(crate_name);
            }
        }
        // the 'proper' case - use the file name part
        bin.push(file.file_name().unwrap());
        let program = bin.with_extension(exe_suffix);
        (file, program)
    };

    if b("run") {
        if ! program.exists() {
            args.quit(&format!("program {:?} does not exist",program));
        }
    } else {
        if ! compile_crate(&args,&state,"",&rust_file,Some(&program), externs, Vec::new()) {
            return;
        }
        if verbose {
            println!("compiled {:?} successfully",rust_file);
        }
    }

    if b("compile-only") {
        let file_name = rust_file.file_name().or_die("no file name?");
        let home = crate_utils::cargo_home().join("bin");
        if ! home.is_dir() {
            // With Windows, standalone installer does not create this directory
            // (may well be a Bugge)
            fs::create_dir(&home).or_die("could not create Cargo bin directory");
            println!("creating Cargo bin directory {}\nEnsure it is on your PATH",home.display());
        }
        let here = home.join(file_name).with_extension(exe_suffix);
        println!("Copying {} to {}",program.display(),here.display());
        fs::copy(&program,&here).or_die("cannot copy program");
        return;
    }

    // Finally run the compiled program
    let ch = cache::get_cache(&state);
    let mut builder = process::Command::new(&program);
    if ! state.build_static {
        // must make the dynamic cache visible to the program!
        if cfg!(windows) {
            // Windows resolves DLL references on the PATH
            let path = env::var("PATH").unwrap();
            let new_path = format!("{};{}",path,ch.display());
            builder.env("PATH",new_path);
        } else {
            // whereas POSIX requires LD_LIBRARY_PATH
            builder.env("LD_LIBRARY_PATH",format!("{}:{}",*RUSTUP_LIB,ch.display()));
        }
    }
    builder.args(&program_args)
        .status()
        .or_then_die(|e| format!("can't run program {:?}: {}",program,e));
}

<commit_msg>arg comments now start with '//: ' and can appear in source file<commit_after>//! A Rust snippet runner.
//!
//! Please see [readme](https://github.com/stevedonovan/runner/blob/master/readme.md)
extern crate easy_shortcuts as es;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate serde_derive;
use lapp;
use shlex;

use es::traits::*;
use std::process;
use std::env;
use std::fs;
use std::path::{Path,PathBuf};
use std::collections::{HashSet};
use std::env::consts::EXE_SUFFIX;

mod crate_utils;
mod platform;
mod strutil;
mod meta;
mod cargo_lock;
mod cache;
mod state;
mod compile;

use platform::{open,edit};
use crate_utils::RUSTUP_LIB;
use state::State;
use compile::{compile_crate,massage_snippet};

const VERSION: &str = "0.4.0";

const USAGE: &str = "
Compile and run small Rust snippets
  -s, --static build statically (default is dynamic)
  -d, --dynamic overrides --static in env.rs
  -O, --optimize optimized static build
  -e, --expression evaluate an expression
  -i, --iterator iterate over an expression
  -n, --lines evaluate expression over stdin; the var 'line' is defined
  -x, --extern... (string) add an extern crate to the snippet
  -X, --wild... (string) like -x but implies wildcard import
  -M, --macro... (string) like -x but implies macro import
  -p, --prepend (default '') put this statement in body (useful for -i etc)
  -N, --no-prelude do not include runner prelude
  -c, --compile-only  will not run program and copies it into ~/.cargo/bin
  -r, --run  don't compile, only re-run
  -S, --no-simplify by default, attempt to simplify rustc error messages
  -E, --edition (default '2015') Rust edition

  Cache Management:
  --add  (string...) add new crates to the cache
  --update update all, or a specific package given as argument
  --edit  edit the static cache Cargo.toml
  --build rebuild the static cache
  --cleanup clean out stale rlibs from cache
  --crates current crates and their versions in cache
  --doc  display documentation (any argument will be specific crate name)
  --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)
  -L, --link (string) path for extra libraries
  --cfg... (string) pass configuration variables to rustc
  --features (string...) enable features in compilation
  --libc  link dynamically against libc (special case)
  (--extern is used to explicitly link in a crate by name)

  -v, --verbose describe what's happening
  -V, --version version of runner

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

fn read_file_with_arg_comment(args: &mut lapp::Args, file: &Path) -> (String,bool) {
    let contents = fs::read_to_string(file).or_die("cannot read file");
    let first_line = contents.lines().next().or_die("empty file");
    let arg_comment = "//: ";
    let has_arg_comment = first_line.starts_with(arg_comment);
    if has_arg_comment {
        let default_args = &first_line[arg_comment.len()..];
        let default_args = shlex::split(default_args).or_die("bad comment args");
        args.parse_command_line(default_args).or_die("cannot parse comment args");
        args.clear_used();
    }
    (contents,has_arg_comment)

}

fn main() {
    let mut args = lapp::Args::new(USAGE);
    args.parse_spec().or_die("bad spec");
    let env = Path::new("env.rs");
    let env_prelude = if env.exists() {
        let (contents,_) = read_file_with_arg_comment(&mut args, env);
        Some(contents)
    } else {
        None
    };

    args.parse_env_args().or_die("bad command line");

    let program_contents = if let Ok(program) = args.get_string_result("program") {
        let prog = Path::new(&program);
        if prog.is_file() && program.ends_with(".rs") {
            args.clear_used();
            let (contents,has_arg_comment) = read_file_with_arg_comment(&mut args, prog);
            if has_arg_comment {
                args.parse_env_args().or_die("bad command line");
            }
            Some(contents)
        } else {
            None
        }
    } else {
        None
    };

    let mut prelude = cache::get_prelude();
    if let Some(env_prelude) = env_prelude {
        prelude.insert_str(0, &env_prelude);
    }
    let b = |p| args.get_bool(p);

    let exe_suffix = if EXE_SUFFIX.len() > 0 {
        &EXE_SUFFIX[1..]
    } else {
        ""
    };

    if b("version") {
        println!("runner {}",VERSION);
        return;
    }
    let verbose = b("verbose");

    if b("run") && b("compile-only") {
        args.quit("--run and compile-only make no sense together");
    }

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

    if b("edit-prelude") {
        let rdir = cache::runner_directory().join("prelude");
        edit(&rdir);
        return;
    }

    // Static Cache Management
    let crates = args.get_strings("add");
    if crates.len() > 0 {
        cache::create_static_cache(&crates);
        return;
    }

    // operations on the static cache
    let (edit_toml, build, doc, update, cleanup, crates) =
        (b("edit"), b("build"), b("doc"), b("update"), b("cleanup"), b("crates"));

    if edit_toml || build || doc || update || cleanup || crates {
        let maybe_argument = args.get_string_result("program");
        let static_cache = cache::static_cache_dir_check();
        if build || update {
            env::set_current_dir(&static_cache).or_die("static cache wasn't a directory?");
            if build {
                cache::build_static_cache();
            } else {
                if let Ok(package) = maybe_argument {
                    cache::cargo(&["update","--package",&package]);
                } else {
                    cache::cargo(&["update"]);
                }
                return;
            }
        } else
        if doc {
            let the_crate = crate_utils::proper_crate_name(
                &if let Ok(file) =  maybe_argument {
                    file
                } else {
                    "static_cache".to_string()
                }
            );
            let docs = static_cache.join(&format!("target/doc/{}/index.html",the_crate));
            open(&docs);
        } else
        if cleanup {
            cache::cargo(&["clean"]);
        } else
        if crates {
            let mut m = cache::get_metadata();
            let mut crates = Vec::new();
            if let Some(name) = maybe_argument.ok() {
                crates.push(name);
                crates.extend(args.get_strings("args"));
            }
            m.dump_crates(crates, verbose);
        } else { // must be edit_toml
            let toml = static_cache.join("Cargo.toml");
            edit(&toml);
        }
        return;
    }

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

    // Dynamically linking crates (experimental!)
    let (print_path, compile) = (b("crate-path"),b("compile"));
    if print_path || compile {
        let state = State::dll(optimized, &edition);
        // plain-jane name is a crate name!
        if crate_utils::plain_name(&first_arg) {
            // but is it one of Ours? Then we definitely know what the
            // actual crate name is AND where the source is cached
            let m = cache::get_metadata();
            if let Some(e) = m.get_meta_entry(&first_arg) {
                if e.path == Path::new("") {
                    args.quit("please run 'runner --build' to update metadata");
                }
                if print_path {
                   // will be <cargo dir>/src/FILE.rs
                    let path = e.path.parent().unwrap().parent().unwrap();
                    println!("{}",path.display());
                } else {
                    // TBD can override --features with features actually
                    // used to build this crate
                    let build_features = &e.features;
                    println!("building crate '{}' {} at {}",e.crate_name, build_features, e.path.display());
                    compile_crate(&args, &state, &e.crate_name, &e.path, None,
                        Vec::new(),
                        build_features.split_whitespace().map(|s| s.to_string()).collect()
                    );
                }
                return;
            }
        } else
        if compile { // either a cargo directory or a Rust source file
            if ! file.exists() {
                args.quit("no such file or directory");
            }
            let (crate_name, crate_path) = if file.is_dir() {
                match crate_utils::cargo_dir(&file) {
                    Ok((path,cargo_toml)) => {
                        // this is somewhat dodgy, since the default location can be changed
                        // Safest bet is to add the crate to the runner static cache
                        let source = path.join("src").join("lib.rs");
                        let name = crate_utils::crate_name(&cargo_toml);
                        (name, source)
                    },
                    Err(msg) => args.quit(&msg)
                }
            } 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(""));
                (name, file.clone())
            };
            println!("building crate '{}' at {}",crate_name, crate_path.display());
            compile_crate(&args, &state, &crate_name, &crate_path, None,  Vec::new(),Vec::new());
            return;
        } else { // we no longer go for wild goose chase to find crates in the Cargo cache
            args.quit("not found in the static cache");
        }
    }

    let static_state = b("static") && ! b("dynamic");
    let state = State::exe(static_state,optimized, &edition);

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

    let mut expression = true;
    use cache::quote;
    let mut code = if b("expression") {
        // Evaluating an expression: just debug print it out.
        format!("println!(\"{{:?}}\",{});", quote(first_arg))
    } else
    if b("iterator") {
        // The expression is anything that implements IntoIterator
        format!("for val in {} {{\n println!(\"{{:?}}\",val);\n}}", quote(first_arg))
    } else
    if b("lines") {
        // The variable 'line' is available to an expression, evaluated for each line in stdin
        // But if the expression ends with '}' then don't dump out this value!
        let first_arg = quote(first_arg);
        let stmt = first_arg.trim_end().ends_with('}');
        let mut s = String::from("
            let stdin = io::stdin();
            for line in stdin.lock().lines() {
                let line = line?;
        ");
        s += &if ! stmt {
            format!("let val = {};\nprintln!(\"{{:?}}\",val);", first_arg)
        } else {
            format!("  {};",first_arg)
        };
        s += "\n}";
        s
    } else { // otherwise, just a file
        expression = false;
        program_contents.or_die("no .rs file")
    };

    // ALL executables go into the Runner bin directory...
    let mut bin = cache::runner_directory().join("bin");
    let mut externs = Vec::new();

    // proper Rust programs are accepted (this is a bit rough)
    let proper = code.find("fn main").is_some();
    let (rust_file, program) = if ! proper {
        // otherwise we must create a proper program from the snippet
        // and write this as a file in the Runner bin directory...
        let mut extern_crates = args.get_strings("extern");
        let wild_crates = args.get_strings("wild");
        let macro_crates = args.get_strings("macro");
        if wild_crates.len() > 0 {
            extern_crates.extend(wild_crates.iter().cloned());
        }
        if macro_crates.len() > 0 {
            extern_crates.extend(macro_crates.iter().cloned());
        }
        let macro_crates: HashSet<_> = macro_crates.into_iter().collect();

        let mut extra = args.get_string("prepend");
        if ! extra.is_empty() {
            extra.push(';');
        }
        let maybe_prelude = if b("no-prelude") {
            "".into()
        } else {
            prelude
        };

        let (massaged_code, deduced_externs)
            = massage_snippet(code, maybe_prelude, extern_crates, wild_crates, macro_crates, extra);
        code = massaged_code;
        externs = deduced_externs;
        if ! expression {
            bin.push(&file);
            bin.set_extension("rs");
        } else { // we make up a name...
            bin.push("tmp.rs");
        }
        fs::write(&bin,&code).or_die("cannot write code");
        let program = bin.with_extension(exe_suffix);
        (bin, program)
    } else {
        for line in code.lines() {
            if let Some(crate_name) = strutil::word_after(line,"extern crate ") {
                externs.push(crate_name);
            }
        }
        // the 'proper' case - use the file name part
        bin.push(file.file_name().unwrap());
        let program = bin.with_extension(exe_suffix);
        (file, program)
    };

    if b("run") {
        if ! program.exists() {
            args.quit(&format!("program {:?} does not exist",program));
        }
    } else {
        if ! compile_crate(&args,&state,"",&rust_file,Some(&program), externs, Vec::new()) {
            return;
        }
        if verbose {
            println!("compiled {:?} successfully",rust_file);
        }
    }

    if b("compile-only") {
        let file_name = rust_file.file_name().or_die("no file name?");
        let home = crate_utils::cargo_home().join("bin");
        if ! home.is_dir() {
            // With Windows, standalone installer does not create this directory
            // (may well be a Bugge)
            fs::create_dir(&home).or_die("could not create Cargo bin directory");
            println!("creating Cargo bin directory {}\nEnsure it is on your PATH",home.display());
        }
        let here = home.join(file_name).with_extension(exe_suffix);
        println!("Copying {} to {}",program.display(),here.display());
        fs::copy(&program,&here).or_die("cannot copy program");
        return;
    }

    // Finally run the compiled program
    let ch = cache::get_cache(&state);
    let mut builder = process::Command::new(&program);
    if ! state.build_static {
        // must make the dynamic cache visible to the program!
        if cfg!(windows) {
            // Windows resolves DLL references on the PATH
            let path = env::var("PATH").unwrap();
            let new_path = format!("{};{}",path,ch.display());
            builder.env("PATH",new_path);
        } else {
            // whereas POSIX requires LD_LIBRARY_PATH
            builder.env("LD_LIBRARY_PATH",format!("{}:{}",*RUSTUP_LIB,ch.display()));
        }
    }
    builder.args(&program_args)
        .status()
        .or_then_die(|e| format!("can't run program {:?}: {}",program,e));
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate serenity;
extern crate chrono;
extern crate rand;
extern crate time;
#[macro_use(object)] extern crate json;

use std::string::*;
use serenity::model::*;
use serenity::Result as SerenityResult;
use serenity::Client;
use serenity::framework::standard::help_commands;
use serenity::framework::StandardFramework;
use serenity::client::{EventHandler,Context, CACHE};
use std::env;
use std::ascii::AsciiExt;
use std::time::{SystemTime, UNIX_EPOCH};
use serenity::model::permissions::Permissions;
use std::path::Path;
use std::path::PathBuf;

mod commands;

struct Handler;

impl EventHandler for Handler {
    fn on_ready(&self, ctx: Context, ready: Ready) {
        	println!("{} is connected!", ready.user.name);
		ctx.set_game_name("lelcp.github.io/bot");
	}
	fn on_message(&self, _: Context, message: Message) {
		let guild_id = match CACHE.read().unwrap().guild_channel(message.channel_id) {
			Some(channel) => channel.read().unwrap().guild_id,
			None => {
				check_msg(message.channel_id.say(&"Groups and DMs not supported"));
				return ();
			},
		};
		if !message.author.bot {
			if message.content.to_ascii_lowercase().contains("thx") || message.content.to_ascii_lowercase().contains("thank"){
				let start = SystemTime::now();
	    			let since_the_epoch = start.duration_since(UNIX_EPOCH)
	       			.expect("Time went backwards");
	       			if message.mentions.len() > 0 {
				if since_the_epoch.as_secs() >= commands::pierogi::time_pierogi(&message.author.id.to_string(),&guild_id.to_string()) {
					let mut msg: String = "".to_string();
						for mention in message.mentions {
							if message.author.id != mention.id {
								msg = format!("{} <@{}>",msg,mention.id);
								let pierogi = commands::pierogi::read_pierogi(&mention.id.to_string(),&guild_id.to_string());
								commands::pierogi::new_pierogi(&mention.id.to_string(), &guild_id.to_string(), pierogi + 1, commands::pierogi::time_pierogi(&mention.id.to_string(),&guild_id.to_string()));
								commands::pierogi::new_pierogi(&message.author.id.to_string(), &guild_id.to_string(), commands::pierogi::read_pierogi(&message.author.id.to_string(),&guild_id.to_string()), since_the_epoch.as_secs() + 7140);
							}
						}
						if msg != "".to_string() {
							check_msg(message.channel_id.say(&format!("You recived thank you pieróg {}",msg)));
						}
					}
					else {
						check_msg(message.channel_id.say(format!("<@{}>, I know your mommy told you to thank as much as you can, but this is too much",message.author.id)));
					}
				}
			}
			let home = env::var("HOME")
				.expect("Expected a token in the environment");
			if Path::new(&format!("{}/.lcpae/commands/{}/{}.json", home, guild_id, message.content)).exists() {
				let path = PathBuf::from(&format!("{}/.lcpae/commands/{}/{}.json", home, guild_id, message.content));
				let text = commands::misc::read_to_string(&path);
				let parsed = json::parse(&text).unwrap();
				if parsed["image"].as_str().unwrap() != "" {
					let _ = message.channel_id.send_message(|m| m
						.embed(|e| e
						.image(parsed["image"].as_str().unwrap())
					));
				}
				if parsed["text"].as_str().unwrap() != "" {
					check_msg(message.channel_id.say(&parsed["text"].as_str().unwrap()));
				}
			}
		}
	}
}

fn main() {

	let token = env::var("DISCORD_TOKEN")
		.expect("Expected a token in the environment");
	let mut client = Client::new(&token, Handler);
	client.with_framework(StandardFramework::new()
		.before(|_ctx, msg, _cmd_name| {
			println!("{} in {}: {}", msg.author.id, msg.channel_id, msg.content);
			true
		})
		.after(|_ctx, _msg, cmd_name, error| {
			if let Err(why) = error {
				println!("Error in {}: {:?}", cmd_name, why);
			}
		})
		.bucket("basic", 5, 60, 3)
		.configure(|c| c
			.prefix("!")
			.on_mention(true)
			.case_insensitivity(true))
		.group("Miscellaneous", |g| g
			.command("gnu", |c| c
				.desc("GNU Interjection copypasta")
				.usage("<GNU replacement> <Linux replacement>")
				.exec(commands::misc::gnu))
			.command("whiteface", |c| c
				.desc("This is not the gif on the internet")
				.exec(commands::misc::whiteface))
			.command("godtellmeyourways", |c| c
				.desc("Quote God himself, Richard Matthew Stallman")
				.exec(commands::misc::god))
			.command("donkey", |c| c
				.desc("Show current bot time and set nickname and playing message")
				.exec(commands::misc::donkey)))
		.group("Useful shit", |g| g
			.command("ddg", |c| c
				.desc("Powerful search with embeds")
				.usage("<search terms>")
				.exec(commands::useful::ddg))
			.command("emoji", |c| c
				.desc(":regional_indicator_s::regional_indicator_p::regional_indicator_e::regional_indicator_a::regional_indicator_k:   :regional_indicator_i::regional_indicator_n:   :regional_indicator_e::regional_indicator_m::regional_indicator_o::regional_indicator_j::regional_indicator_i:")
				.usage("<your text>")
				.bucket("basic")
				.exec(commands::useful::emoji))
			.command("info", |c| c
				.desc("Distro database")
				.usage("<distro name>")
				.exec(commands::useful::info))
			.command("wget", |c| c
				.desc("Sends wget script")
				.usage("<amount of messages in hundreds to download from channel>")
				.exec(commands::useful::wget)))
		.group("About bot", |g| g
			.command("github", |c| c
				.desc("Shilling open source nature of this project")
				.exec(commands::about::github))
			.command("rust", |c| c
				.desc("Shilling rust nature of this project")
				.exec(commands::about::rust))
			.command("lcpae", |c| c
				.exec_help(help_commands::with_embeds)))
		.group("Tux", |g| g
			.command("roasted", |c| c
				.desc("Daaaaaamn!")
				.exec(commands::tux::roasted))
			.command("hypertux", |c| c
				.desc("Laugh all you want")
				.exec(commands::tux::hypertux))
			.command("hyperthink", |c| c
				.desc("TFW hacked mainframe")
				.exec(commands::tux::hyperthink)))
		.group("Admin", |g| g
			.required_permissions(Permissions::ADMINISTRATOR)
			.command("clear", |c| c
				.desc("Clean previous messages")
				.exec(commands::admin::clear))
			.command("ccommand", |c| c
				.desc("Custom commands")
				.exec(commands::admin::ccommand)))
		.group("Pierogi", |g| g
			.prefix("pierog")
			.command("score", |c| c
				.desc("Check your own score")
				.exec(commands::pierogi::score))
			.command("steal", |c| c
				.desc("Steal pierogi, but be careful")
				.exec(commands::pierogi::steal))
			.command("give", |c| c
				.desc("Steal pierogi, but be careful")
				.exec(commands::pierogi::give))

		));
	let _ = client.start().map_err(|why| println!("Client ended: {:?}", why));
}

fn check_msg(result: SerenityResult<Message>) {
	if let Err(why) = result {
		println!("Error sending message: {:?}", why);
	}
}
<commit_msg>Improved thank you function<commit_after>#[macro_use]
extern crate serenity;
extern crate chrono;
extern crate rand;
extern crate time;
#[macro_use(object)] extern crate json;

use std::string::*;
use serenity::model::*;
use serenity::Result as SerenityResult;
use serenity::Client;
use serenity::framework::standard::help_commands;
use serenity::framework::StandardFramework;
use serenity::client::{EventHandler,Context, CACHE};
use std::env;
use std::ascii::AsciiExt;
use std::time::{SystemTime, UNIX_EPOCH};
use serenity::model::permissions::Permissions;
use std::path::Path;
use std::path::PathBuf;

mod commands;

struct Handler;

impl EventHandler for Handler {
    fn on_ready(&self, ctx: Context, ready: Ready) {
        	println!("{} is connected!", ready.user.name);
		ctx.set_game_name("lelcp.github.io/bot");
	}
	fn on_message(&self, _: Context, message: Message) {
		let guild_id = match CACHE.read().unwrap().guild_channel(message.channel_id) {
			Some(channel) => channel.read().unwrap().guild_id,
			None => {
				check_msg(message.channel_id.say(&"Groups and DMs not supported"));
				return ();
			},
		};
		if !message.author.bot {
			if message.content.to_ascii_lowercase().contains("thx") || message.content.to_ascii_lowercase().contains("thank"){
				let start = SystemTime::now();
				let mut botmention = false;
	    			let since_the_epoch = start.duration_since(UNIX_EPOCH)
	       			.expect("Time went backwards");
	       			if message.mentions.len() > 0 {
				if since_the_epoch.as_secs() >= commands::pierogi::time_pierogi(&message.author.id.to_string(),&guild_id.to_string()) {
					let mut msg: String = "".to_string();
						for mention in message.mentions {
							if message.author.id != mention.id {
								msg = format!("{} <@{}>",msg,mention.id);
								let pierogi = commands::pierogi::read_pierogi(&mention.id.to_string(),&guild_id.to_string());
								commands::pierogi::new_pierogi(&mention.id.to_string(), &guild_id.to_string(), pierogi + 1, commands::pierogi::time_pierogi(&mention.id.to_string(),&guild_id.to_string()));
								commands::pierogi::new_pierogi(&message.author.id.to_string(), &guild_id.to_string(), commands::pierogi::read_pierogi(&message.author.id.to_string(),&guild_id.to_string()), since_the_epoch.as_secs() + 7140);
								if mention.id == CACHE.read().unwrap().user.id {
									botmention = true;
									commands::pierogi::new_pierogi(&message.author.id.to_string(), &guild_id.to_string(), commands::pierogi::read_pierogi(&message.author.id.to_string(),&guild_id.to_string()) + 1, since_the_epoch.as_secs() + 7140);
								}
							}
						}
						if msg != "".to_string() {
							if botmention {
								check_msg(message.channel_id.say(&format!("You recived thank you pieróg {}. Oh wait, pierogi for me? ***THANK YOU SO MUCH, YOU TOO GET A PIERÓG***",msg)));
							}
							else {
								check_msg(message.channel_id.say(&format!("You recived thank you pieróg {}",msg)));
							}
						}
					}
					else {
						check_msg(message.channel_id.say(format!("<@{}>, I know your mommy told you to thank as much as you can, but this is too much",message.author.id)));
					}
				}
			}
			let home = env::var("HOME")
				.expect("Expected a token in the environment");
			if Path::new(&format!("{}/.lcpae/commands/{}/{}.json", home, guild_id, message.content)).exists() {
				let path = PathBuf::from(&format!("{}/.lcpae/commands/{}/{}.json", home, guild_id, message.content));
				let text = commands::misc::read_to_string(&path);
				let parsed = json::parse(&text).unwrap();
				if parsed["image"].as_str().unwrap() != "" {
					let _ = message.channel_id.send_message(|m| m
						.embed(|e| e
						.image(parsed["image"].as_str().unwrap())
					));
				}
				if parsed["text"].as_str().unwrap() != "" {
					check_msg(message.channel_id.say(&parsed["text"].as_str().unwrap()));
				}
			}
		}
	}
}

fn main() {

	let token = env::var("DISCORD_TOKEN")
		.expect("Expected a token in the environment");
	let mut client = Client::new(&token, Handler);
	client.with_framework(StandardFramework::new()
		.before(|_ctx, msg, _cmd_name| {
			println!("{} in {}: {}", msg.author.id, msg.channel_id, msg.content);
			true
		})
		.after(|_ctx, _msg, cmd_name, error| {
			if let Err(why) = error {
				println!("Error in {}: {:?}", cmd_name, why);
			}
		})
		.bucket("basic", 5, 60, 3)
		.configure(|c| c
			.prefix("!")
			.on_mention(true)
			.case_insensitivity(true))
		.group("Miscellaneous", |g| g
			.command("gnu", |c| c
				.desc("GNU Interjection copypasta")
				.usage("<GNU replacement> <Linux replacement>")
				.exec(commands::misc::gnu))
			.command("whiteface", |c| c
				.desc("This is not the gif on the internet")
				.exec(commands::misc::whiteface))
			.command("godtellmeyourways", |c| c
				.desc("Quote God himself, Richard Matthew Stallman")
				.exec(commands::misc::god))
			.command("donkey", |c| c
				.desc("Show current bot time and set nickname and playing message")
				.exec(commands::misc::donkey)))
		.group("Useful shit", |g| g
			.command("ddg", |c| c
				.desc("Powerful search with embeds")
				.usage("<search terms>")
				.exec(commands::useful::ddg))
			.command("emoji", |c| c
				.desc(":regional_indicator_s::regional_indicator_p::regional_indicator_e::regional_indicator_a::regional_indicator_k:   :regional_indicator_i::regional_indicator_n:   :regional_indicator_e::regional_indicator_m::regional_indicator_o::regional_indicator_j::regional_indicator_i:")
				.usage("<your text>")
				.bucket("basic")
				.exec(commands::useful::emoji))
			.command("info", |c| c
				.desc("Distro database")
				.usage("<distro name>")
				.exec(commands::useful::info))
			.command("wget", |c| c
				.desc("Sends wget script")
				.usage("<amount of messages in hundreds to download from channel>")
				.exec(commands::useful::wget)))
		.group("About bot", |g| g
			.command("github", |c| c
				.desc("Shilling open source nature of this project")
				.exec(commands::about::github))
			.command("rust", |c| c
				.desc("Shilling rust nature of this project")
				.exec(commands::about::rust))
			.command("lcpae", |c| c
				.exec_help(help_commands::with_embeds)))
		.group("Tux", |g| g
			.command("roasted", |c| c
				.desc("Daaaaaamn!")
				.exec(commands::tux::roasted))
			.command("hypertux", |c| c
				.desc("Laugh all you want")
				.exec(commands::tux::hypertux))
			.command("hyperthink", |c| c
				.desc("TFW hacked mainframe")
				.exec(commands::tux::hyperthink)))
		.group("Admin", |g| g
			.required_permissions(Permissions::ADMINISTRATOR)
			.command("clear", |c| c
				.desc("Clean previous messages")
				.exec(commands::admin::clear))
			.command("ccommand", |c| c
				.desc("Custom commands")
				.exec(commands::admin::ccommand)))
		.group("Pierogi", |g| g
			.prefix("pierog")
			.command("score", |c| c
				.desc("Check your own score")
				.exec(commands::pierogi::score))
			.command("steal", |c| c
				.desc("Steal pierogi, but be careful")
				.exec(commands::pierogi::steal))
			.command("give", |c| c
				.desc("Steal pierogi, but be careful")
				.exec(commands::pierogi::give))

		));
	let _ = client.start().map_err(|why| println!("Client ended: {:?}", why));
}

fn check_msg(result: SerenityResult<Message>) {
	if let Err(why) = result {
		println!("Error sending message: {:?}", why);
	}
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate devicemapper;
#[macro_use]
extern crate clap;
extern crate nix;

#[allow(unused_imports)]
use std::io;
use std::io::{Read, Write, ErrorKind};
use std::error::Error;
use std::process::exit;
use std::fs::OpenOptions;
use std::path::{Path, PathBuf};

use devicemapper as devm;
use clap::{App, Arg, SubCommand, ArgMatches};
use nix::sys::stat;

static mut debug: bool = false;

macro_rules! dbgp {
    ($($arg:tt)*) => (
        unsafe {
            if debug {
                println!($($arg)*)
            }
        })
}

macro_rules! errp {
    ($($arg:tt)*) => (
        match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        })
}

fn list(args: &ArgMatches) -> io::Result<()> {
    println!("hello from list()");
    Ok(())
}

fn status(args: &ArgMatches) -> io::Result<()> {
    println!("hello from status()");
    Ok(())
}

fn add(args: &ArgMatches) -> io::Result<()> {
    println!("hello from add()");
    Ok(())
}

fn remove(args: &ArgMatches) -> io::Result<()> {
    println!("hello from remove()");
    Ok(())
}

fn create(args: &ArgMatches) -> io::Result<()> {
    let name = args.value_of("froyodevname").unwrap();
    let dev_paths: Vec<_> = args.values_of("devices").unwrap().into_iter()
        .map(|dev| {
            if !Path::new(dev).is_absolute() {
                PathBuf::from(format!("/dev/{}", dev))
            } else {
                PathBuf::from(dev)
            }})
        .collect();

    // do some checks
    for path in &dev_paths {
        let pstat = match stat::stat(path) {
            Err(_) => return Err(io::Error::new(
                ErrorKind::NotFound,
                format!("{} not found", path.display()))),
            Ok(x) => x,
        };

        if pstat.st_mode & 0x6000 != 0x6000 {
            return Err(io::Error::new(
                ErrorKind::InvalidInput,
                format!("{} is not a block device", path.display())));
        }

        let mut f = match OpenOptions::new().read(true).write(true).open(path) {
            Err(_) => {
                return Err(io::Error::new(
                    ErrorKind::PermissionDenied,
                    format!("Could not open {}", path.display())));
            },
            Ok(x) => x,
        };

        let mut buf = [0u8; 4096];
        try!(f.read(&mut buf));

        if buf.iter().any(|x| *x != 0) {
            return Err(io::Error::new(
                ErrorKind::InvalidInput,
                format!("First 4K of {} is not zeroed, need to use --force",
                        path.display())));
        }
    }
    Ok(())
}

fn main() {

    let matches = App::new("froyo")
        .version(&crate_version!())
        .author("Andy Grover <andy@groveronline.com>")
        .about("Drobo + Free + YOLO")
        .arg(Arg::with_name("debug")
             .short("d")
             .long("debug")
             .help("Print additional output for debugging")
             )
        .subcommand(SubCommand::with_name("list")
                    .about("List all froyodevs")
                    .arg(Arg::with_name("long")
                         .short("l")
                         .long("long")
                         .help("Use a long listing format")
                         )
                    )
        .subcommand(SubCommand::with_name("status")
                    .about("Get the status of a single froyodev")
                    .arg(Arg::with_name("froyodevname")
                         .required(true)
                         .help("Froyodev to get info on")
                         .index(1)
                         )
                    )
        .subcommand(SubCommand::with_name("add")
                    .about("Add one or more additional block devices to a froyodev")
                    .arg(Arg::with_name("froyodevname")
                         .help("Froyodev to add the device to")
                         .required(true)
                         .index(1)
                         )
                    .arg(Arg::with_name("devices")
                         .help("device(s) to add")
                         .multiple(true)
                         .required(true)
                         .index(2)
                         )
                    )
        .subcommand(SubCommand::with_name("remove")
                    .about("Remove a block device from a froyodev")
                    .arg(Arg::with_name("froyodevname")
                         .help("Froyodev to remove the device from")
                         .required(true)
                         .index(1)
                         )
                    .arg(Arg::with_name("devices")
                         .help("Block device(s) to remove")
                         .multiple(true)
                         .required(true)
                         .index(2)
                         )
                    )
        .subcommand(SubCommand::with_name("create")
                    .about("Create a new froyodev")
                    .arg(Arg::with_name("force")
                         .short("f")
                         .long("force")
                         .help("Force")
                         )
                    .arg(Arg::with_name("froyodevname")
                         .help("Name of the new froyodev")
                         .required(true)
                         .index(1)
                         )
                    .arg(Arg::with_name("devices")
                         .help("Initial block device(s) to use")
                         .multiple(true)
                         .required(true)
                         .index(2)
                         )
                    )
        .get_matches();

    if matches.is_present("debug") {
        // must use unsafe to change a mut static, sigh
        unsafe { debug = true };
    }

    let r = match matches.subcommand() {
        ("list", Some(matches)) => list(matches),
        ("status", Some(matches)) => status(matches),
        ("add", Some(matches)) => add(matches),
        ("remove", Some(matches)) => remove(matches),
        ("create", Some(matches)) => create(matches),
        ("", None) => {
            println!("No command given, try \"help\"");
            Ok(())
        }
        _ => unreachable!(),
    };

    if let Err(r) = r {
        errp!("{}", r.description());
        exit(1);
    };
}
<commit_msg>Move code into Froyo and FroyoDev objects<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate devicemapper;
#[macro_use]
extern crate clap;
extern crate nix;

#[allow(unused_imports)]
use std::io;
use std::io::{Read, Write, ErrorKind};
use std::error::Error;
use std::process::exit;
use std::fs::OpenOptions;
use std::path::{Path, PathBuf};
use std::str::FromStr;

use devicemapper as devm;
use devicemapper::Device;
use clap::{App, Arg, SubCommand, ArgMatches};
use nix::sys::stat;

static mut debug: bool = false;

macro_rules! dbgp {
    ($($arg:tt)*) => (
        unsafe {
            if debug {
                println!($($arg)*)
            }
        })
}

macro_rules! errp {
    ($($arg:tt)*) => (
        match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        })
}

struct FroyoDev {
    dev: Device,
}

impl FroyoDev {
    fn new(dev: Device) -> io::Result<FroyoDev> {
        unimplemented!()
    }

    fn initialize(f: &mut Froyo, dev: Device, force: bool) -> io::Result<FroyoDev> {
        let pathbuf = try!(dev.path().ok_or(io::Error::new(
            ErrorKind::NotFound,
            format!("Could not get path for {}:{}", dev.major, dev.minor))));

        let pstat = match stat::stat(&pathbuf) {
            Err(_) => return Err(io::Error::new(
                ErrorKind::NotFound,
                format!("{} not found", &pathbuf.display()))),
            Ok(x) => x,
        };

        if pstat.st_mode & 0x6000 != 0x6000 {
            return Err(io::Error::new(
                ErrorKind::InvalidInput,
                format!("{} is not a block device", &pathbuf.display())));
        }

        let mut f = match OpenOptions::new().read(true).write(true).open(&pathbuf) {
            Err(_) => {
                return Err(io::Error::new(
                    ErrorKind::PermissionDenied,
                    format!("Could not open {}", &pathbuf.display())));
            },
            Ok(x) => x,
        };

        if !force {
            let mut buf = [0u8; 4096];
            try!(f.read(&mut buf));

            if buf.iter().any(|x| *x != 0) {
                return Err(io::Error::new(
                    ErrorKind::InvalidInput,
                    format!("First 4K of {} is not zeroed, need to use --force",
                            &pathbuf.display())));
            }
        }

        println!("initialize the blockdev!");

        Ok(FroyoDev {dev: dev})
    }
}

struct Froyo {
    name: String,
    devs: Vec<FroyoDev>,
}

impl Froyo {
    fn new(name: &str) -> Froyo {
        Froyo {
            name: name.to_string(),
            devs: Vec::new(),
        }
    }
}

fn list(args: &ArgMatches) -> io::Result<()> {
    println!("hello from list()");
    Ok(())
}

fn status(args: &ArgMatches) -> io::Result<()> {
    println!("hello from status()");
    Ok(())
}

fn add(args: &ArgMatches) -> io::Result<()> {
    println!("hello from add()");
    Ok(())
}

fn remove(args: &ArgMatches) -> io::Result<()> {
    println!("hello from remove()");
    Ok(())
}

fn create(args: &ArgMatches) -> io::Result<()> {
    let name = args.value_of("froyodevname").unwrap();
    let dev_paths: Vec<_> = args.values_of("devices").unwrap().into_iter()
        .map(|dev| {
            if !Path::new(dev).is_absolute() {
                PathBuf::from(format!("/dev/{}", dev))
            } else {
                PathBuf::from(dev)
            }})
        .collect();

    let mut froyo = Froyo::new(name);

    for path in dev_paths {
        let dev = match Device::from_str(&path.to_string_lossy()) {
            Ok(x) => x,
            Err(_) => return Err(io::Error::new(
                ErrorKind::InvalidInput,
                format!("{} is not a block device", path.display())))
        };

        dbgp!("Initializing {}", &path.display());
        let fd = try!(FroyoDev::initialize(&mut froyo, dev, args.is_present("force")));
    }

    // TODO: Build froyodev on top of our newly created blockdevs

    Ok(())
}

fn main() {

    let matches = App::new("froyo")
        .version(&crate_version!())
        .author("Andy Grover <andy@groveronline.com>")
        .about("Drobo + Free + YOLO")
        .arg(Arg::with_name("debug")
             .short("d")
             .long("debug")
             .help("Print additional output for debugging")
             )
        .subcommand(SubCommand::with_name("list")
                    .about("List all froyodevs")
                    .arg(Arg::with_name("long")
                         .short("l")
                         .long("long")
                         .help("Use a long listing format")
                         )
                    )
        .subcommand(SubCommand::with_name("status")
                    .about("Get the status of a single froyodev")
                    .arg(Arg::with_name("froyodevname")
                         .required(true)
                         .help("Froyodev to get info on")
                         .index(1)
                         )
                    )
        .subcommand(SubCommand::with_name("add")
                    .about("Add one or more additional block devices to a froyodev")
                    .arg(Arg::with_name("froyodevname")
                         .help("Froyodev to add the device to")
                         .required(true)
                         .index(1)
                         )
                    .arg(Arg::with_name("devices")
                         .help("device(s) to add")
                         .multiple(true)
                         .required(true)
                         .index(2)
                         )
                    )
        .subcommand(SubCommand::with_name("remove")
                    .about("Remove a block device from a froyodev")
                    .arg(Arg::with_name("froyodevname")
                         .help("Froyodev to remove the device from")
                         .required(true)
                         .index(1)
                         )
                    .arg(Arg::with_name("devices")
                         .help("Block device(s) to remove")
                         .multiple(true)
                         .required(true)
                         .index(2)
                         )
                    )
        .subcommand(SubCommand::with_name("create")
                    .about("Create a new froyodev")
                    .arg(Arg::with_name("force")
                         .short("f")
                         .long("force")
                         .help("Force")
                         )
                    .arg(Arg::with_name("froyodevname")
                         .help("Name of the new froyodev")
                         .required(true)
                         .index(1)
                         )
                    .arg(Arg::with_name("devices")
                         .help("Initial block device(s) to use")
                         .multiple(true)
                         .required(true)
                         .index(2)
                         )
                    )
        .get_matches();

    if matches.is_present("debug") {
        // must use unsafe to change a mut static, sigh
        unsafe { debug = true };
    }

    let r = match matches.subcommand() {
        ("list", Some(matches)) => list(matches),
        ("status", Some(matches)) => status(matches),
        ("add", Some(matches)) => add(matches),
        ("remove", Some(matches)) => remove(matches),
        ("create", Some(matches)) => create(matches),
        ("", None) => {
            println!("No command given, try \"help\"");
            Ok(())
        }
        _ => unreachable!(),
    };

    if let Err(r) = r {
        errp!("{}", r.description());
        exit(1);
    };
}
<|endoftext|>


<commit_before>mod error;
mod pos;
mod token;
mod scanner;
mod types;
mod ast;
mod parser;
mod typecheck;
mod cgen;

use token::{Token, TokenType};
use error::Error;
use scanner::Scanner;
use parser::Parser;
use typecheck::TypeChecker;

use std::io::{Read, stdin};
use std::env;

#[derive(PartialEq, Eq)]
enum Command {
    Scan,
    Parse,
    Typecheck,
    Codegen,
}

fn compile(cmd: Command) -> Result<(), Error> {
    let mut data = String::new();
    let _ = stdin().read_to_string(&mut data);
    let data = data;
    let mut scanner = Scanner::new(&data);

    let mut tokens: Vec<Token> = Vec::new();

    loop {
        let tok = try!(scanner.next_token());
        let is_eof = tok.typ == TokenType::Eof;
        tokens.push(tok);
        if is_eof {
            break;
        }
    }

    if cmd == Command::Scan {
        for tok in tokens {
            println!("{:?}", tok);
        }
        return Ok(());
    }

    let mut parser = Parser::new(tokens);
    let program = try!(parser.parse_program());

    if cmd == Command::Parse {
        println!("{:?}", program);
        return Ok(());
    }

    let mut typechecker = TypeChecker::new();
    try!(typechecker.tc_program(&program));

    if cmd == Command::Typecheck {
        println!("SYMBOL TABLE");
        println!("============");
        for (id, ty) in &typechecker.symtable {
            println!("{}: {:?}", id, ty);
        }

        println!("");

        println!("EXPRESSION TABLE");
        println!("================");
        for (expr, ty) in &typechecker.expr_table {
            println!("{:?}: {:?}", expr, ty);
        }
        return Ok(())
    }

    cgen::codegen(&program, &typechecker.symtable, &typechecker.expr_table);

    Ok(())
}

fn usage() {
    match env::current_exe() {
        Ok(path) => { println!("Usage: {} <scan | parse | typecheck | codegen>", path.display()); }
        Err(_) => { println!("Usage: minic <scan | parse | typecheck | codegen>"); }
    }
}

fn main() {
    match env::args().nth(1) {
        Some(cmd) => {
            let res =
                if cmd == "scan" {
                    compile(Command::Scan)
                } else if cmd == "parse" {
                    compile(Command::Parse)
                } else if cmd == "typecheck" {
                    compile(Command::Typecheck)
                } else if cmd == "codegen" {
                    compile(Command::Codegen)
                } else {
                    Err(Error::UsageError)
                };
            match res {
                Ok(()) => (),
                Err(Error::UsageError) => usage(),
                Err(e) => { println!("Error: {}", e); }
            }

        }
        None => usage()
    }
}
<commit_msg>Add clap support<commit_after>extern crate clap;
use clap::{App, Arg, SubCommand};

mod error;
mod pos;
mod token;
mod scanner;
mod types;
mod ast;
mod parser;
mod typecheck;
mod cgen;

use token::{Token, TokenType};
use error::Error;
use scanner::Scanner;
use parser::Parser;
use typecheck::TypeChecker;

use std::io::{Read, stdin};
use std::process;

fn scan(display_tokens: bool) {
    let mut stdin = stdin();
    let mut buf = String::new();
    stdin.read_to_string(&mut buf);
    let mut scanner = Scanner::new(&buf);

    loop {
        match scanner.next_token() {
            Err(err) => {
                println!("{:?}", err);
                process::exit(1)
            }
            Ok(Token { typ: TokenType::Eof, .. }) => {}
            Ok(tok) => {
                if display_tokens {
                    println!("{:?}", tok);
                }
            }
        }
    }
}

fn parse(display_ast: bool) {
    let mut stdin = stdin();
    let mut buf = String::new();
    stdin.read_to_string(&mut buf);
    let mut scanner = Scanner::new(&buf);

    let mut tokens = Vec::new();
    loop {
        match scanner.next_token() {
            Ok(tok) => {
                let is_eof = tok.typ == TokenType::Eof;
                tokens.push(tok);
                if is_eof {
                    break;
                }
            }
            Err(err) => {
                println!("{:?}", err);
                process::exit(1);
            }
        }
    }

    let mut parser = Parser::new(tokens);

    match parser.parse_program() {
        Ok(ast) => {
            if display_ast {
                println!("{:#?}", ast);
            }
        }
        Err(err) => {
            println!("{:?}", err);
            process::exit(1);
        }
    }
}

fn main() {
    let compiler_match = App::new("Minilang compiler")
        .version("0.1")
        .author("Vincent Foley <vfoley@gmail.com>")
        .subcommand(SubCommand::with_name("scan")
                    .about("Scan a program; return 0 if valid, 1 otherwise"))

        .subcommand(SubCommand::with_name("tokens")
                    .about("Scan a program and print its tokens one per line"))

        .subcommand(SubCommand::with_name("parse")
                    .about("Parse a program; return 0 if valid, 1 otherwise"))

        .subcommand(SubCommand::with_name("ast")
                    .about("Parse a program and print its AST"))

        .subcommand(SubCommand::with_name("typecheck")
                    .about("Typecheck a program; return 0 if valid, 1 otherwise"))

        .subcommand(SubCommand::with_name("typed-ast")
                    .about("Typecheck a program and print its typed AST"))

        .subcommand(SubCommand::with_name("mips")
                    .about("Generate MIPS code for a program"))

        .get_matches();

    match compiler_match.subcommand_name() {
        Some("scan") => { scan(false) }
        Some("tokens") => { scan(true) }
        Some("parse") => { parse(false) }
        Some("ast") => { parse(true) }
        Some(_) => {}
        None => {
            println!("{}", compiler_match.usage());
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(target_arch = "x86")]
mod defs {
    pub const ULONG_SIZE: usize = 4;
    pub const MACH2PHYS_VIRT_START: usize = 0xF5800000;
    pub const FLAT_KERNEL_CS: u16 = 0xe019;
}

#[cfg(target_arch = "x86_64")]
mod defs {
    pub const ULONG_SIZE: usize = 8;
    pub const MACH2PHYS_VIRT_START: usize = 0xFFFF800000000000;
    pub const FLAT_KERNEL_CS: u16 = 0xe033;
}

pub use self::defs::*;

pub const XEN_LEGACY_MAX_VCPUS: usize = 32;

/// unsigned long
pub type Ulong = usize;

/// xen_pfn_t
pub type Pfn = Ulong;

/// struct arch_vcpu_info
#[repr(C)]
pub struct ArchVcpuInfo {
    pub cr2: Ulong,
    pub pad: [Ulong; 5],
}

/// struct arch_shared_info
#[repr(C)]
pub struct ArchSharedInfo {
    pub max_pfn: Ulong,
    pub pfn_to_mfn_frame_list_list: Ulong,
    pub nmi_reason: Ulong,
}

/// struct trap_info
#[repr(C)]
pub struct TrapInfo {
    pub vector: u8,
    pub flags: u8,
    pub cs: u16,
    pub address: unsafe extern "C" fn() -> (),
}

impl TrapInfo {
    pub const fn new(vector: u8, flags: u8, cs: u16,
                     address: unsafe extern "C" fn() -> ()) -> Self {
        TrapInfo {
            vector: vector,
            flags: flags,
            cs: cs,
            address: address,
        }
    }
}
<commit_msg>libxen/defs: ArchVcpuInfo is now correct for x86_64<commit_after>#[cfg(target_arch = "x86")]
mod defs {
    pub const ULONG_SIZE: usize = 4;
    pub const MACH2PHYS_VIRT_START: usize = 0xF5800000;
    pub const FLAT_KERNEL_CS: u16 = 0xe019;
}

#[cfg(target_arch = "x86_64")]
mod defs {
    pub const ULONG_SIZE: usize = 8;
    pub const MACH2PHYS_VIRT_START: usize = 0xFFFF800000000000;
    pub const FLAT_KERNEL_CS: u16 = 0xe033;
}

pub use self::defs::*;

pub const XEN_LEGACY_MAX_VCPUS: usize = 32;

/// unsigned long
pub type Ulong = usize;

/// xen_pfn_t
pub type Pfn = Ulong;

/// struct arch_vcpu_info
#[repr(C)]
#[cfg(target_arch = "x86")]
pub struct ArchVcpuInfo {
    pub cr2: Ulong,
    pub pad: [Ulong; 5],
}

/// struct arch_vcpu_info
#[repr(C)]
#[cfg(target_arch = "x86_64")]
pub struct ArchVcpuInfo {
    pub cr2: Ulong,
    pub pad: Ulong,
}

/// struct arch_shared_info
#[repr(C)]
pub struct ArchSharedInfo {
    pub max_pfn: Ulong,
    pub pfn_to_mfn_frame_list_list: Ulong,
    pub nmi_reason: Ulong,
}

/// struct trap_info
#[repr(C)]
pub struct TrapInfo {
    pub vector: u8,
    pub flags: u8,
    pub cs: u16,
    pub address: unsafe extern "C" fn() -> (),
}

impl TrapInfo {
    pub const fn new(vector: u8, flags: u8, cs: u16,
                     address: unsafe extern "C" fn() -> ()) -> Self {
        TrapInfo {
            vector: vector,
            flags: flags,
            cs: cs,
            address: address,
        }
    }
}
<|endoftext|>


<commit_before>
// Copyright 2017 The gltf Library Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::hash_map;
use std::{iter, slice};
use json;

use {Accessor, Gltf, Material};

pub use json::mesh::{Mode, Semantic};

/// Vertex attribute data.
#[derive(Clone, Debug)]
pub enum Attribute<'a> {
    /// Vertex colors.
    Colors(u32, Accessor<'a>),

    /// User specific data.
    #[cfg(feature = "extras")]
    Extras(&'a str, Accessor<'a>),

    /// Vertex joints.
    Joints(u32, Accessor<'a>),

    /// XYZ vertex positions of type `[f32; 3]`.
    Positions(Accessor<'a>),

    /// XYZ vertex normals of type `[f32; 3]`.
    Normals(Accessor<'a>),

    /// XYZW vertex tangents of type `[f32; 4]` where the `w` component is a
    /// sign value (-1 or +1) indicating the handedness of the tangent basis.
    Tangents(Accessor<'a>),

    /// UV texture co-ordinates.
    TexCoords(u32, Accessor<'a>),

    /// Weights.
    Weights(u32, Accessor<'a>),
}

/// Morph targets.
#[derive(Clone, Debug)]
pub struct MorphTargets<'a> {
    /// XYZ vertex position displacements.
    positions: Option<Accessor<'a>>,

    /// XYZ vertex normal displacements.
    normals: Option<Accessor<'a>>,

    /// XYZ vertex tangent displacements.
    tangents: Option<Accessor<'a>>,
}

/// A set of primitives to be rendered.  A node can contain one or more meshes and
/// its transform places the meshes in the scene.
#[derive(Clone, Debug)]
pub struct Mesh<'a>  {
    /// The parent `Gltf` struct.
    gltf: &'a Gltf,

    /// The corresponding JSON index.
    index: usize,

    /// The corresponding JSON struct.
    json: &'a json::mesh::Mesh,
}

/// Geometry to be rendered with the given material.
#[derive(Clone, Debug)]
pub struct Primitive<'a>  {
    /// The parent `Mesh` struct.
    mesh: &'a Mesh<'a>,

    /// The corresponding JSON index.
    index: usize,

    /// The corresponding JSON struct.
    json: &'a json::mesh::Primitive,
}

/// An `Iterator` that visits the attributes of a `Primitive`.
#[derive(Clone, Debug)]
pub struct Attributes<'a> {
    /// The parent `Gltf` struct.
    gltf: &'a Gltf,

    /// The parent `Primitive` struct.
    prim: &'a Primitive<'a>,

    /// The internal attribute iterator.
    iter: hash_map::Iter<
        'a,
        json::validation::Checked<json::mesh::Semantic>,
        json::Index<json::accessor::Accessor>,
    >,
}

/// An `Iterator` that visits the primitives of a `Mesh`.
#[derive(Clone, Debug)]
pub struct Primitives<'a>  {
    /// The parent `Mesh` struct.
    mesh: &'a Mesh<'a>,

    /// The internal JSON primitive iterator.
    iter: iter::Enumerate<slice::Iter<'a, json::mesh::Primitive>>,
}

impl<'a> Mesh<'a>  {
    /// Constructs a `Mesh`.
    pub(crate) fn new(
        gltf: &'a Gltf,
        index: usize,
        json: &'a json::mesh::Mesh,
    ) -> Self {
        Self {
            gltf: gltf,
            index: index,
            json: json,
        }
    }

    /// Returns the internal JSON index.
    pub fn index(&self) -> usize {
        self.index
    }

    /// Returns the internal JSON item.
    pub fn as_json(&self) ->  &json::mesh::Mesh {
        self.json
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    pub fn name(&self) -> Option<&str> {
        self.json.name.as_ref().map(String::as_str)
    }

    /// Defines the geometry to be renderered with a material.
    pub fn primitives(&'a self) -> Primitives<'a> {
        Primitives {
            mesh: self,
            iter: self.json.primitives.iter().enumerate(),
        }
    }

    /// Defines the weights to be applied to the morph targets.
    pub fn weights(&self) -> Option<&[f32]> {
        self.json.weights.as_ref().map(Vec::as_slice)
    }
}

impl<'a> Primitive<'a> {
    /// Constructs a `Primitive`.
    pub(crate) fn new(
        mesh: &'a Mesh<'a>,
        index: usize,
        json: &'a json::mesh::Primitive,
    ) -> Self {
        Self {
            mesh: mesh,
            index: index,
            json: json,
        }
    }

    /// Returns the internal JSON item.
    pub fn as_json(&self) ->  &json::mesh::Primitive {
        self.json
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }

    /// Return the accessor with the given semantic.
    pub fn get(&self, semantic: &Semantic) -> Option<Accessor> {
        self.json.attributes
            .get(&json::validation::Checked::Valid(semantic.clone()))
            .map(|index| self.mesh.gltf.accessors().nth(index.value()).unwrap())
    }

    /// Returns the accessor containing the primitive indices, if provided.
    pub fn indices(&self) -> Option<Accessor> {
        self.json.indices
            .as_ref()
            .map(|index| self.mesh.gltf.accessors().nth(index.value()).unwrap())
    }

    /// Returns an `Iterator` that visits the vertex attributes.
    pub fn attributes(&self) -> Attributes {
        Attributes {
            gltf: self.mesh.gltf,
            prim: self,
            iter: self.json.attributes.iter(),
        }
    }

    /// Returns the material to apply to this primitive when rendering
    pub fn material(&self) -> Material {
        self.json.material
            .as_ref()
            .map(|index| self.mesh.gltf.materials().nth(index.value()).unwrap())
            .unwrap_or_else(|| Material::default(self.mesh.gltf))
    }

    /// The type of primitives to render.
    pub fn mode(&self) -> Mode {
        self.json.mode.unwrap()
    }
}

impl<'a> Iterator for Attributes<'a> {
    type Item = Attribute<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        use self::Semantic::*;
        self.iter
            .next()
            .map(|(ref key, ref index)| {
                let semantic = key.as_ref().unwrap();
                let accessor = self.gltf.accessors().nth(index.value()).unwrap();
                match *semantic {
                    Positions => Attribute::Positions(accessor),
                    Normals => Attribute::Normals(accessor),
                    Tangents => Attribute::Tangents(accessor),
                    Colors(set) => Attribute::Colors(set, accessor),
                    TexCoords(set) => Attribute::TexCoords(set, accessor),
                    Joints(set) => Attribute::Joints(set, accessor),
                    Weights(set) => Attribute::Weights(set, accessor),
                    #[cfg(feature = "extras")]
                    Extras(ref id) => Attribute::Extras(id, accessor),
                }
            })
    }
}

impl<'a> Iterator for Primitives<'a> {
    type Item = Primitive<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|(index, json)| Primitive::new(self.mesh, index, json))
    }
}
<commit_msg>Primitive wrapper: add bounds(), refactor find_accessor_with_semantic()<commit_after>
// Copyright 2017 The gltf Library Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::hash_map;
use std::{iter, slice};
use json;

use {Accessor, Gltf, Material};

pub use json::mesh::{Mode, Semantic};
use json::validation::Checked;

/// Vertex attribute data.
#[derive(Clone, Debug)]
pub enum Attribute<'a> {
    /// Vertex colors.
    Colors(u32, Accessor<'a>),

    /// User specific data.
    #[cfg(feature = "extras")]
    Extras(&'a str, Accessor<'a>),

    /// Vertex joints.
    Joints(u32, Accessor<'a>),

    /// XYZ vertex positions of type `[f32; 3]`.
    Positions(Accessor<'a>),

    /// XYZ vertex normals of type `[f32; 3]`.
    Normals(Accessor<'a>),

    /// XYZW vertex tangents of type `[f32; 4]` where the `w` component is a
    /// sign value (-1 or +1) indicating the handedness of the tangent basis.
    Tangents(Accessor<'a>),

    /// UV texture co-ordinates.
    TexCoords(u32, Accessor<'a>),

    /// Weights.
    Weights(u32, Accessor<'a>),
}

/// Morph targets.
#[derive(Clone, Debug)]
pub struct MorphTargets<'a> {
    /// XYZ vertex position displacements.
    positions: Option<Accessor<'a>>,

    /// XYZ vertex normal displacements.
    normals: Option<Accessor<'a>>,

    /// XYZ vertex tangent displacements.
    tangents: Option<Accessor<'a>>,
}

/// A set of primitives to be rendered.  A node can contain one or more meshes and
/// its transform places the meshes in the scene.
#[derive(Clone, Debug)]
pub struct Mesh<'a>  {
    /// The parent `Gltf` struct.
    gltf: &'a Gltf,

    /// The corresponding JSON index.
    index: usize,

    /// The corresponding JSON struct.
    json: &'a json::mesh::Mesh,
}

/// Geometry to be rendered with the given material.
#[derive(Clone, Debug)]
pub struct Primitive<'a>  {
    /// The parent `Mesh` struct.
    mesh: &'a Mesh<'a>,

    /// The corresponding JSON index.
    index: usize,

    /// The corresponding JSON struct.
    json: &'a json::mesh::Primitive,
}

/// An `Iterator` that visits the attributes of a `Primitive`.
#[derive(Clone, Debug)]
pub struct Attributes<'a> {
    /// The parent `Gltf` struct.
    gltf: &'a Gltf,

    /// The parent `Primitive` struct.
    prim: &'a Primitive<'a>,

    /// The internal attribute iterator.
    iter: hash_map::Iter<
        'a,
        json::validation::Checked<json::mesh::Semantic>,
        json::Index<json::accessor::Accessor>,
    >,
}

/// An `Iterator` that visits the primitives of a `Mesh`.
#[derive(Clone, Debug)]
pub struct Primitives<'a>  {
    /// The parent `Mesh` struct.
    mesh: &'a Mesh<'a>,

    /// The internal JSON primitive iterator.
    iter: iter::Enumerate<slice::Iter<'a, json::mesh::Primitive>>,
}

impl<'a> Mesh<'a>  {
    /// Constructs a `Mesh`.
    pub(crate) fn new(
        gltf: &'a Gltf,
        index: usize,
        json: &'a json::mesh::Mesh,
    ) -> Self {
        Self {
            gltf: gltf,
            index: index,
            json: json,
        }
    }

    /// Returns the internal JSON index.
    pub fn index(&self) -> usize {
        self.index
    }

    /// Returns the internal JSON item.
    pub fn as_json(&self) ->  &json::mesh::Mesh {
        self.json
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    pub fn name(&self) -> Option<&str> {
        self.json.name.as_ref().map(String::as_str)
    }

    /// Defines the geometry to be renderered with a material.
    pub fn primitives(&'a self) -> Primitives<'a> {
        Primitives {
            mesh: self,
            iter: self.json.primitives.iter().enumerate(),
        }
    }

    /// Defines the weights to be applied to the morph targets.
    pub fn weights(&self) -> Option<&[f32]> {
        self.json.weights.as_ref().map(Vec::as_slice)
    }
}

/// Accessor bounds
#[derive(Debug)]
pub struct Bounds {
    min: [f32; 3],
    max: [f32; 3]
}

impl<'a> Primitive<'a> {
    /// Constructs a `Primitive`.
    pub(crate) fn new(
        mesh: &'a Mesh<'a>,
        index: usize,
        json: &'a json::mesh::Primitive,
    ) -> Self {
        Self {
            mesh: mesh,
            index: index,
            json: json,
        }
    }

    /// Returns the internal JSON item.
    pub fn as_json(&self) ->  &json::mesh::Primitive {
        self.json
    }

    /// Returns the min and max of the POSITION attribute if there is one.
    pub fn bounds(&self) -> Option<Bounds> {
        if let Some(pos_accessor_index) = self.json.attributes.get(&Checked::Valid(Semantic::Positions)) {
            let pos_accessor = self.mesh.gltf.accessors().nth(pos_accessor_index.value()).unwrap();
            let min: [f32; 3] = json::from_value(pos_accessor.min().unwrap()).unwrap();
            let max: [f32; 3] = json::from_value(pos_accessor.max().unwrap()).unwrap();
            Some(Bounds {
                min: [min[0], min[1], min[2]],
                max: [max[0], max[1], max[2]]
            })
        }
        else {
            None
        }
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }

    /// Return the accessor with the given semantic.
    pub fn get(&self, semantic: &Semantic) -> Option<Accessor> {
        self.json.attributes
            .get(&json::validation::Checked::Valid(semantic.clone()))
            .map(|index| self.mesh.gltf.accessors().nth(index.value()).unwrap())
    }

    /// Returns the accessor containing the primitive indices, if provided.
    pub fn indices(&self) -> Option<Accessor> {
        self.json.indices
            .as_ref()
            .map(|index| self.mesh.gltf.accessors().nth(index.value()).unwrap())
    }

    /// Returns an `Iterator` that visits the vertex attributes.
    pub fn attributes(&self) -> Attributes {
        Attributes {
            gltf: self.mesh.gltf,
            prim: self,
            iter: self.json.attributes.iter(),
        }
    }

    /// Returns the material to apply to this primitive when rendering
    pub fn material(&self) -> Material {
        self.json.material
            .as_ref()
            .map(|index| self.mesh.gltf.materials().nth(index.value()).unwrap())
            .unwrap_or_else(|| Material::default(self.mesh.gltf))
    }

    /// The type of primitives to render.
    pub fn mode(&self) -> Mode {
        self.json.mode.unwrap()
    }
}

impl<'a> Iterator for Attributes<'a> {
    type Item = Attribute<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        use self::Semantic::*;
        self.iter
            .next()
            .map(|(ref key, ref index)| {
                let semantic = key.as_ref().unwrap();
                let accessor = self.gltf.accessors().nth(index.value()).unwrap();
                match *semantic {
                    Positions => Attribute::Positions(accessor),
                    Normals => Attribute::Normals(accessor),
                    Tangents => Attribute::Tangents(accessor),
                    Colors(set) => Attribute::Colors(set, accessor),
                    TexCoords(set) => Attribute::TexCoords(set, accessor),
                    Joints(set) => Attribute::Joints(set, accessor),
                    Weights(set) => Attribute::Weights(set, accessor),
                    #[cfg(feature = "extras")]
                    Extras(ref id) => Attribute::Extras(id, accessor),
                }
            })
    }
}

impl<'a> Iterator for Primitives<'a> {
    type Item = Primitive<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|(index, json)| Primitive::new(self.mesh, index, json))
    }
}
<|endoftext|>