<commit_before>extern crate ansi_term;
#[macro_use]
extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate flexi_logger;
extern crate futures;
#[macro_use]
extern crate log;
extern crate mhost;
extern crate tokio_core;
extern crate trust_dns;

use mhost::{Query, Response, multiple_lookup};
use mhost::lookup::{self, Result as LookupResult};
use mhost::get;
use mhost::output::{self, OutputModule};

use ansi_term::Colour;
use clap::{App, Arg, ArgMatches, Shell};
use flexi_logger::{Logger, LogRecord};
use futures::Future;
use log::LogLevel;
use std::net::IpAddr;
use std::str::FromStr;
use std::time::Duration;
use tokio_core::reactor::Core;
use trust_dns::rr::RecordType;

fn run() -> Result<()> {
    let args = build_cli().get_matches();

    init_looger(args.occurrences_of("verbosity"))
        .start()
        .unwrap_or_else(|e| { panic!("Logger initialization failed with {}", e) });

    if args.is_present("completions") {
        return generate_completion(&args);
    }

    let (query, server_limit) = parse_args(&args)?;
    let responses = run_lookup(&args, query, server_limit);
    // TODO: https://github.com/kbknapp/clap-rs/issues/1056
    let output_modules = match args.values_of_lossy("output modules") {
        Some(v) => v,
        None => vec!["summar".to_string()],
    };
    output(&responses, output_modules, args.is_present("human-readable output"))?;

    Ok(())
}

fn build_cli() -> App<'static, 'static> {
    let name = env!("CARGO_PKG_NAME");
    let version = env!("CARGO_PKG_VERSION");
    let about = env!("CARGO_PKG_DESCRIPTION");

    App::new(name)
        .version(version)
        .about(about)
        .arg(
            Arg::with_name("domain name")
                .index(1)
                .required(true)
                .conflicts_with("completions")
                .help("domain name or IP address to look up")
        )
        .arg(
            Arg::with_name("timeout")
                .long("timeout")
                .default_value("5")
                .help("Sets timeout for server responses in sec")
                .takes_value(true)
        )
        .arg(
            Arg::with_name("record types")
                .long("type")
                .short("t")
                .takes_value(true)
                .multiple(true)
                .require_delimiter(true)
                .possible_values(
                    &[
                        "a",
                        "aaaa",
                        "any",
                        "cname",
                        "dnskey",
                        "mx",
                        "ns",
                        "opt",
                        "ptr",
                        "soa",
                        "srv",
                        "txt",
                    ],
                )
                .help("Selects resource record type [default: a, aaaa, mx]")
        )
        .arg(
            Arg::with_name("dont use local dns servers")
                .short("L")
                .help("Ignore local DNS servers from /etc/resolv.conf")
        )
        .arg(
            Arg::with_name("dont use local search domain")
                .short("S")
                .help("Ignore local search domains from /etc/resolv.conf")
        )
        .arg(Arg::with_name("predefined server").short("p").help(
            "Uses predefined DNS servers set"
        ))
        .arg(
            Arg::with_name("DNS servers")
                .long("server")
                .short("s")
                .takes_value(true)
                .multiple(true)
                .require_delimiter(true)
                .number_of_values(1)
                .help(
                    "Sets DNS servers to use"
                )
        )
        .arg(
            Arg::with_name("ungefiltert ids")
                .short("u")
                .takes_value(true)
                .multiple(true)
                .require_delimiter(true)
                .help("Retrieves DNS servers from https://www.ungefiltert-surfen.de/ for country ids, e.g., 'de'")
        )
        .arg(
            Arg::with_name("limit")
                .long("limit")
                .short("l")
                .default_value("100")
                .help("Limits the amount of servers to query")
                .takes_value(true)
        )
        .arg(
            Arg::with_name("output modules")
                .long("module")
                .short("m")
                .takes_value(true)
                .multiple(true)
                .require_delimiter(true)
                // TODO: https://github.com/kbknapp/clap-rs/issues/1056: .default_value("summary")
                .possible_values(
                    &[
                        "summary",
                        "details",
                    ],
                )
                .help("Selects output module")
        )
        .arg(
            Arg::with_name("human-readable output")
                .short("h")
                .help("Sets human-readable output")
        )
        .arg(Arg::with_name("verbosity")
            .short("v")
            .multiple(true)
            .help("Sets level of verbosity")
        )
        .arg(
            Arg::with_name("completions")
                .long("completions")
                .takes_value(true)
                .hidden(true)
                .possible_values(&["bash", "fish", "zsh"])
                .help("The shell to generate the script for")
        )
}

fn init_looger(verbosity_level: u64) -> Logger {
    fn colour(l: LogLevel) -> Colour {
        match l {
            LogLevel::Error => Colour::Red,
            LogLevel::Warn => Colour::Yellow,
            LogLevel::Info => Colour::Blue,
            _ => Colour::White,
        }
    }

    fn log_format_info(r: &LogRecord) -> String {
        format!("{}", colour(r.level()).paint(
            format!("{}: {}",
                    r.location().module_path(),
                    &r.args()
            )
        ))
    }

    fn log_format_debug(r: &LogRecord) -> String {
        format!("{}", colour(r.level()).paint(
            format!("{}:{}:{}: {}",
                    r.location().module_path(),
                    r.location().file(),
                    r.location().line(),
                    &r.args()
            )
        ))
    }

    let (log_spec, log_format): (String, fn(&LogRecord) -> String) = match std::env::var("RUST_LOG") {
        Ok(spec) => (spec, log_format_debug),
        Err(_) if verbosity_level == 1 => ("mhost=info".to_string(), log_format_info),
        Err(_) if verbosity_level == 2 => ("mhost=debug".to_string(), log_format_debug),
        Err(_) if verbosity_level > 2 => ("mhost=trace".to_string(), log_format_debug),
        Err(_) => ("mhost=warn".to_string(), log_format_info),
    };

    Logger::with_str(&log_spec).format(log_format)
}

fn generate_completion(args: &ArgMatches) -> Result<()> {
    let bin_name = env!("CARGO_PKG_NAME");
    let shell = args.value_of("completions").ok_or(
        ErrorKind::CliArgsParsingError,
    )?;
    build_cli().gen_completions_to(
        bin_name,
        shell.parse::<Shell>().unwrap(),
        &mut std::io::stdout(),
    );
    Ok(())
}

fn parse_args(args: &ArgMatches) -> Result<(Query, usize)> {
    let timeout = value_t!(args, "timeout", u64)
        .map(Duration::from_secs)
        .unwrap();

    let domain_name = if args.is_present("dont use local search domain") {
        args.value_of("domain name").unwrap().to_string()
    } else {
        let cfg = get::resolv_conf()?;
        let domain_name_from_args = args.value_of("domain name").unwrap();
        if domain_name_from_args.ends_with('.') {
            domain_name_from_args.to_string()
        } else if !cfg.search.is_empty() && domain_name_from_args.matches('.').count() >= cfg.ndots as usize {
            format!("{}.", domain_name_from_args)
        } else {
            format!("{}.{}.", domain_name_from_args, cfg.search.first().unwrap())
        }
    };
    debug!("domain_name: '{}'", domain_name);

    let query = match IpAddr::from_str(&domain_name) {
        Ok(ip) => Query::from(ip, vec![RecordType::PTR]),
        Err(_) => {
            let record_types = get::record_types(args.values_of_lossy("record types"))
                .chain_err(|| ErrorKind::CliArgsParsingError)?;
            Query::new(&domain_name, record_types)
        }
    }.set_timeout(timeout);
    trace!("{:?}", query);

    let server_limit = value_t!(args, "limit", usize).unwrap();

    Ok((query, server_limit))
}

// TODO: make this a Result
fn run_lookup(args: &ArgMatches, query: Query, server_limit: usize) -> Vec<LookupResult<Response>> {
    let mut io_loop = Core::new().unwrap();
    let handle = io_loop.handle();
    let lookup = get::dns_servers(
        &handle,
        args.values_of_lossy("DNS servers"),
        args.is_present("predefined server"),
        args.is_present("dont use local dns servers"),
        args.values_of_lossy("ungefiltert ids"),
    )
        .map_err(|e| e.into())
        .and_then(|servers| {
            debug!("DNS Server set: {:?}", servers);
            let dns_endpoints = servers
                .into_iter()
                .map(|s| (s, 53))
                .take(server_limit)
                .collect();
            multiple_lookup(&handle, query, dns_endpoints).map_err(
                |_| {
                    Error::from_kind(ErrorKind::LookupFailed)
                },
            )
        });
    let result = io_loop.run(lookup);

    result.unwrap()
}

fn output(responses: &[LookupResult<Response>], outputs: Vec<String>, human: bool) -> Result<()> {
    let mut writer = std::io::stdout();
    for output in outputs {
        match output.as_ref() {
            "details" => output::DetailsOutput::new(responses, human).output(&mut writer)?,
            _ => output::SummaryOutput::new(responses, human).output(&mut writer)?,
        }
    }

    Ok(())
}

error_chain! {
    errors {
        CliArgsParsingError {
            description("failed to parse CLI arguments")
            display("failed to parse CLI arguments")
        }

        LookupFailed {
            description("failed to run lookup")
            display("failed to run lookup")
        }
    }

    links {
        Get(get::Error, get::ErrorKind);
        Lookup(lookup::Error, lookup::ErrorKind);
        Output(output::Error, output::ErrorKind);
    }
}

quick_main!(run);
<commit_msg>Fix bug re/ building ptr query in binary<commit_after>extern crate ansi_term;
#[macro_use]
extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate flexi_logger;
extern crate futures;
#[macro_use]
extern crate log;
extern crate mhost;
extern crate tokio_core;
extern crate trust_dns;

use mhost::{Query, Response, multiple_lookup};
use mhost::lookup::{self, Result as LookupResult};
use mhost::get;
use mhost::output::{self, OutputModule};

use ansi_term::Colour;
use clap::{App, Arg, ArgMatches, Shell};
use flexi_logger::{Logger, LogRecord};
use futures::Future;
use log::LogLevel;
use std::net::IpAddr;
use std::str::FromStr;
use std::time::Duration;
use tokio_core::reactor::Core;
use trust_dns::rr::RecordType;

fn run() -> Result<()> {
    let args = build_cli().get_matches();

    init_looger(args.occurrences_of("verbosity"))
        .start()
        .unwrap_or_else(|e| { panic!("Logger initialization failed with {}", e) });

    if args.is_present("completions") {
        return generate_completion(&args);
    }

    let (query, server_limit) = parse_args(&args)?;
    let responses = run_lookup(&args, query, server_limit);
    // TODO: https://github.com/kbknapp/clap-rs/issues/1056
    let output_modules = match args.values_of_lossy("output modules") {
        Some(v) => v,
        None => vec!["summar".to_string()],
    };
    output(&responses, output_modules, args.is_present("human-readable output"))?;

    Ok(())
}

fn build_cli() -> App<'static, 'static> {
    let name = env!("CARGO_PKG_NAME");
    let version = env!("CARGO_PKG_VERSION");
    let about = env!("CARGO_PKG_DESCRIPTION");

    App::new(name)
        .version(version)
        .about(about)
        .arg(
            Arg::with_name("domain name")
                .index(1)
                .required(true)
                .conflicts_with("completions")
                .help("domain name or IP address to look up")
        )
        .arg(
            Arg::with_name("timeout")
                .long("timeout")
                .default_value("5")
                .help("Sets timeout for server responses in sec")
                .takes_value(true)
        )
        .arg(
            Arg::with_name("record types")
                .long("type")
                .short("t")
                .takes_value(true)
                .multiple(true)
                .require_delimiter(true)
                .possible_values(
                    &[
                        "a",
                        "aaaa",
                        "any",
                        "cname",
                        "dnskey",
                        "mx",
                        "ns",
                        "opt",
                        "ptr",
                        "soa",
                        "srv",
                        "txt",
                    ],
                )
                .help("Selects resource record type [default: a, aaaa, mx]")
        )
        .arg(
            Arg::with_name("dont use local dns servers")
                .short("L")
                .help("Ignore local DNS servers from /etc/resolv.conf")
        )
        .arg(
            Arg::with_name("dont use local search domain")
                .short("S")
                .help("Ignore local search domains from /etc/resolv.conf")
        )
        .arg(Arg::with_name("predefined server").short("p").help(
            "Uses predefined DNS servers set"
        ))
        .arg(
            Arg::with_name("DNS servers")
                .long("server")
                .short("s")
                .takes_value(true)
                .multiple(true)
                .require_delimiter(true)
                .number_of_values(1)
                .help(
                    "Sets DNS servers to use"
                )
        )
        .arg(
            Arg::with_name("ungefiltert ids")
                .short("u")
                .takes_value(true)
                .multiple(true)
                .require_delimiter(true)
                .help("Retrieves DNS servers from https://www.ungefiltert-surfen.de/ for country ids, e.g., 'de'")
        )
        .arg(
            Arg::with_name("limit")
                .long("limit")
                .short("l")
                .default_value("100")
                .help("Limits the amount of servers to query")
                .takes_value(true)
        )
        .arg(
            Arg::with_name("output modules")
                .long("module")
                .short("m")
                .takes_value(true)
                .multiple(true)
                .require_delimiter(true)
                // TODO: https://github.com/kbknapp/clap-rs/issues/1056: .default_value("summary")
                .possible_values(
                    &[
                        "summary",
                        "details",
                    ],
                )
                .help("Selects output module")
        )
        .arg(
            Arg::with_name("human-readable output")
                .short("h")
                .help("Sets human-readable output")
        )
        .arg(Arg::with_name("verbosity")
            .short("v")
            .multiple(true)
            .help("Sets level of verbosity")
        )
        .arg(
            Arg::with_name("completions")
                .long("completions")
                .takes_value(true)
                .hidden(true)
                .possible_values(&["bash", "fish", "zsh"])
                .help("The shell to generate the script for")
        )
}

fn init_looger(verbosity_level: u64) -> Logger {
    fn colour(l: LogLevel) -> Colour {
        match l {
            LogLevel::Error => Colour::Red,
            LogLevel::Warn => Colour::Yellow,
            LogLevel::Info => Colour::Blue,
            _ => Colour::White,
        }
    }

    fn log_format_info(r: &LogRecord) -> String {
        format!("{}", colour(r.level()).paint(
            format!("{}: {}",
                    r.location().module_path(),
                    &r.args()
            )
        ))
    }

    fn log_format_debug(r: &LogRecord) -> String {
        format!("{}", colour(r.level()).paint(
            format!("{}:{}:{}: {}",
                    r.location().module_path(),
                    r.location().file(),
                    r.location().line(),
                    &r.args()
            )
        ))
    }

    let (log_spec, log_format): (String, fn(&LogRecord) -> String) = match std::env::var("RUST_LOG") {
        Ok(spec) => (spec, log_format_debug),
        Err(_) if verbosity_level == 1 => ("mhost=info".to_string(), log_format_info),
        Err(_) if verbosity_level == 2 => ("mhost=debug".to_string(), log_format_debug),
        Err(_) if verbosity_level > 2 => ("mhost=trace".to_string(), log_format_debug),
        Err(_) => ("mhost=warn".to_string(), log_format_info),
    };

    Logger::with_str(&log_spec).format(log_format)
}

fn generate_completion(args: &ArgMatches) -> Result<()> {
    let bin_name = env!("CARGO_PKG_NAME");
    let shell = args.value_of("completions").ok_or(
        ErrorKind::CliArgsParsingError,
    )?;
    build_cli().gen_completions_to(
        bin_name,
        shell.parse::<Shell>().unwrap(),
        &mut std::io::stdout(),
    );
    Ok(())
}

fn parse_args(args: &ArgMatches) -> Result<(Query, usize)> {
    let timeout = value_t!(args, "timeout", u64)
        .map(Duration::from_secs)
        .unwrap();

    let query = match IpAddr::from_str(args.value_of("domain name").unwrap() ) {
        Ok(ip) => Query::from(ip, vec![RecordType::PTR]),
        Err(_) => {
            let domain_name = if args.is_present("dont use local search domain") {
                args.value_of("domain name").unwrap().to_string()
            } else {
                let cfg = get::resolv_conf()?;
                let domain_name_from_args = args.value_of("domain name").unwrap();
                if domain_name_from_args.ends_with('.') {
                    domain_name_from_args.to_string()
                } else if !cfg.search.is_empty() && domain_name_from_args.matches('.').count() >= cfg.ndots as usize {
                    format!("{}.", domain_name_from_args)
                } else {
                    format!("{}.{}.", domain_name_from_args, cfg.search.first().unwrap())
                }
            };
            debug!("domain_name: '{}'", domain_name);

            let record_types = get::record_types(args.values_of_lossy("record types"))
                .chain_err(|| ErrorKind::CliArgsParsingError)?;
            Query::new(&domain_name, record_types)
        }
    }.set_timeout(timeout);
    trace!("{:?}", query);

    let server_limit = value_t!(args, "limit", usize).unwrap();

    Ok((query, server_limit))
}

// TODO: make this a Result
fn run_lookup(args: &ArgMatches, query: Query, server_limit: usize) -> Vec<LookupResult<Response>> {
    let mut io_loop = Core::new().unwrap();
    let handle = io_loop.handle();
    let lookup = get::dns_servers(
        &handle,
        args.values_of_lossy("DNS servers"),
        args.is_present("predefined server"),
        args.is_present("dont use local dns servers"),
        args.values_of_lossy("ungefiltert ids"),
    )
        .map_err(|e| e.into())
        .and_then(|servers| {
            debug!("DNS Server set: {:?}", servers);
            let dns_endpoints = servers
                .into_iter()
                .map(|s| (s, 53))
                .take(server_limit)
                .collect();
            multiple_lookup(&handle, query, dns_endpoints).map_err(
                |_| {
                    Error::from_kind(ErrorKind::LookupFailed)
                },
            )
        });
    let result = io_loop.run(lookup);

    result.unwrap()
}

fn output(responses: &[LookupResult<Response>], outputs: Vec<String>, human: bool) -> Result<()> {
    let mut writer = std::io::stdout();
    for output in outputs {
        match output.as_ref() {
            "details" => output::DetailsOutput::new(responses, human).output(&mut writer)?,
            _ => output::SummaryOutput::new(responses, human).output(&mut writer)?,
        }
    }

    Ok(())
}

error_chain! {
    errors {
        CliArgsParsingError {
            description("failed to parse CLI arguments")
            display("failed to parse CLI arguments")
        }

        LookupFailed {
            description("failed to run lookup")
            display("failed to run lookup")
        }
    }

    links {
        Get(get::Error, get::ErrorKind);
        Lookup(lookup::Error, lookup::ErrorKind);
        Output(output::Error, output::ErrorKind);
    }
}

quick_main!(run);
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::env;
use std::fs::File;
use std::io::{stdout, stderr, Write};
use std::process::exit;
use coreutils::ArgParser;
use extra::option::OptionalExt;
use extra::io::fail;

const MAN_PAGE: &'static str = /* @MANSTART{touch} */ r#"
NAME
    touch - create file(s)

SYNOPSIS
    touch [ -h | --help ] FILE...

DESCRIPTION
    Create the FILE(s) arguments provided

OPTIONS
    -h
    --help
        display this help and exit
"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    if parser.args.is_empty() {
        fail("no arguments.", &mut stderr);
    }
    else {
        // TODO update file modification date/time
        for arg in env::args().skip(1) {
            File::create(&arg).try(&mut stderr);
        }
    }
}
<commit_msg>Update file time if file exists<commit_after>#![deny(warnings)]

extern crate coreutils;
extern crate extra;
extern crate syscall;

use std::env;
use std::fs::File;
use std::io::{stdout, stderr, Error, Write};
use std::time::{SystemTime, UNIX_EPOCH};
use std::path::Path;
use std::process::exit;
use coreutils::ArgParser;
use extra::option::OptionalExt;
use extra::io::fail;
use syscall::data::TimeSpec;
use syscall::flag::O_WRONLY;

const MAN_PAGE: &'static str = /* @MANSTART{touch} */ r#"
NAME
    touch - create file(s)

SYNOPSIS
    touch [ -h | --help ] FILE...

DESCRIPTION
    Create the FILE(s) arguments provided

OPTIONS
    -h
    --help
        display this help and exit
"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    if parser.args.is_empty() {
        fail("no arguments.", &mut stderr);
    }
    else {
        // TODO update file modification date/time
        for arg in env::args().skip(1) {
            if Path::new(&arg).is_file() {
                let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();

                let file = syscall::open(&arg, O_WRONLY).map_err(|e| Error::from_raw_os_error(e.errno)).try(&mut stderr);
                let res = syscall::futimens(file, &[TimeSpec {
                    tv_sec: mtime.as_secs() as i64,
                    tv_nsec: mtime.subsec_nanos() as i32,
                }]).map_err(|e| Error::from_raw_os_error(e.errno));
                let _ = syscall::close(file);
                res.try(&mut stderr);
            } else {
                File::create(&arg).try(&mut stderr);
            }
        }
    }
}
<|endoftext|>


<commit_before>#![deny(unused)]
#![allow(unstable)]
#![cfg_attr(test, deny(warnings))]

extern crate libc;
extern crate "rustc-serialize" as rustc_serialize;
extern crate regex;
extern crate term;
extern crate time;
#[macro_use] extern crate log;

extern crate curl;
extern crate docopt;
extern crate flate2;
extern crate git2;
extern crate glob;
extern crate semver;
extern crate tar;
extern crate toml;
extern crate url;
#[cfg(test)] extern crate hamcrest;

extern crate registry;

use std::error::Error;
use std::io::stdio::{stdout_raw, stderr_raw};
use std::io::{self, stdout, stderr};
use std::os;
use rustc_serialize::{Decodable, Encodable};
use rustc_serialize::json::{self, Json};
use docopt::Docopt;

use core::{Shell, MultiShell, ShellConfig};
use term::color::{BLACK, RED};

pub use util::{CargoError, CliError, CliResult, human, Config};

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

pub fn execute_main<T, U, V>(
                        exec: fn(T, U, &Config) -> CliResult<Option<V>>,
                        options_first: bool,
                        usage: &str)
    where V: Encodable, T: Decodable, U: Decodable
{
    process::<V, _>(|rest, shell| {
        call_main(exec, shell, usage, rest, options_first)
    });
}

pub fn call_main<T, U, V>(
            exec: fn(T, U, &Config) -> CliResult<Option<V>>,
            shell: &Config,
            usage: &str,
            args: &[String],
            options_first: bool) -> CliResult<Option<V>>
    where V: Encodable, T: Decodable, U: Decodable
{
    let flags = try!(flags_from_args::<T>(usage, args, options_first));
    let json = try!(json_from_stdin::<U>());

    exec(flags, json, shell)
}

pub fn execute_main_without_stdin<T, V>(
                                      exec: fn(T, &Config) -> CliResult<Option<V>>,
                                      options_first: bool,
                                      usage: &str)
    where V: Encodable, T: Decodable
{
    process::<V, _>(|rest, shell| {
        call_main_without_stdin(exec, shell, usage, rest, options_first)
    });
}

pub fn call_main_without_stdin<T, V>(
            exec: fn(T, &Config) -> CliResult<Option<V>>,
            shell: &Config,
            usage: &str,
            args: &[String],
            options_first: bool) -> CliResult<Option<V>>
    where V: Encodable, T: Decodable
{
    let flags = try!(flags_from_args::<T>(usage, args, options_first));
    exec(flags, shell)
}

fn process<V, F>(mut callback: F)
    where F: FnMut(&[String], &Config) -> CliResult<Option<V>>,
          V: Encodable
{
    let mut shell = shell(true);
    process_executed({
        match Config::new(&mut shell) {
            Ok(cfg) => callback(os::args().as_slice(), &cfg),
            Err(e) => Err(CliError::from_boxed(e, 101)),
        }
    }, &mut shell)
}

pub fn process_executed<T>(result: CliResult<Option<T>>, shell: &mut MultiShell)
    where T: Encodable
{
    match result {
        Err(e) => handle_error(e, shell),
        Ok(Some(encodable)) => {
            let encoded = json::encode(&encodable);
            println!("{}", encoded);
        }
        _ => {}
    }
}

pub fn shell(verbose: bool) -> MultiShell {
    let tty = stderr_raw().isatty();
    let stderr = Box::new(stderr()) as Box<Writer + Send>;

    let config = ShellConfig { color: true, verbose: verbose, tty: tty };
    let err = Shell::create(stderr, config);

    let tty = stdout_raw().isatty();
    let stdout = Box::new(stdout()) as Box<Writer + Send>;

    let config = ShellConfig { color: true, verbose: verbose, tty: tty };
    let out = Shell::create(stdout, config);

    MultiShell::new(out, err, verbose)
}

// `output` print variant error strings to either stderr or stdout.
// For fatal errors, print to stderr;
// and for others, e.g. docopt version info, print to stdout.
fn output(caption: Option<&str>, detail: Option<String>,
          shell: &mut MultiShell, fatal: bool) {
    let std_shell = if fatal {shell.err()} else {shell.out()};
    if let Some(caption) = caption {
        let color = if fatal {RED} else {BLACK};
        let _ = std_shell.say(caption, color);
    }
    if let Some(detail) = detail {
        let _ = std_shell.say(detail, BLACK); // always black
    }
}

pub fn handle_error(err: CliError, shell: &mut MultiShell) {
    log!(4, "handle_error; err={:?}", err);

    let CliError { error, exit_code, unknown } = err;
    let fatal = exit_code != 0; // exit_code == 0 is non-fatal error

    let desc = error.description();
    if unknown {
        output(Some("An unknown error occurred"), None, shell, fatal);
    } else if desc.len() > 0 {
        output(Some(desc), None, shell, fatal);
    }
    if shell.get_verbose() {
        output(None, error.detail(), shell, fatal);
    }
    if !handle_cause(&*error, shell) {
        let _ = shell.err().say("\nTo learn more, run the command again \
                                 with --verbose.".to_string(), BLACK);
    }

    std::os::set_exit_status(exit_code as isize);
}

fn handle_cause(mut cargo_err: &CargoError, shell: &mut MultiShell) -> bool {
    let verbose = shell.get_verbose();
    let mut err;
    loop {
        cargo_err = match cargo_err.cargo_cause() {
            Some(cause) => cause,
            None => { err = cargo_err.cause(); break }
        };
        if !verbose && !cargo_err.is_human() { return false }
        print(cargo_err.description(), cargo_err.detail(), shell);
    }
    loop {
        let cause = match err { Some(err) => err, None => return true };
        if !verbose { return false }
        print(cause.description(), cause.detail(), shell);
        err = cause.cause();
    }

    fn print(desc: &str, detail: Option<String>, shell: &mut MultiShell) {
        let _ = shell.err().say("\nCaused by:", BLACK);
        let _ = shell.err().say(format!("  {}", desc), BLACK);
        if shell.get_verbose() {
            if let Some(detail) = detail {
                let _ = shell.err().say(detail, BLACK);
            }
        }
    }
}

pub fn version() -> String {
    format!("cargo {}", match option_env!("CFG_VERSION") {
        Some(s) => s.to_string(),
        None => format!("{}.{}.{}{}",
                        env!("CARGO_PKG_VERSION_MAJOR"),
                        env!("CARGO_PKG_VERSION_MINOR"),
                        env!("CARGO_PKG_VERSION_PATCH"),
                        option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""))
    })
}

fn flags_from_args<'a, T>(usage: &str, args: &[String],
                          options_first: bool) -> CliResult<T>
    where T: Decodable
{
    struct CargoDocoptError { err: docopt::Error }
    impl Error for CargoDocoptError {
        fn description(&self) -> &str {
            match self.err {
                docopt::Error::WithProgramUsage(..) => "",
                ref e if e.fatal() => self.err.description(),
                _ => "",
            }
        }

        fn detail(&self) -> Option<String> {
            match self.err {
                docopt::Error::WithProgramUsage(_, ref usage) => {
                    Some(usage.clone())
                }
                ref e if e.fatal() => None,
                ref e => Some(e.to_string())
            }
        }
    }
    impl CargoError for CargoDocoptError {
        fn is_human(&self) -> bool { true }
    }

    let docopt = Docopt::new(usage).unwrap()
                                   .options_first(options_first)
                                   .argv(args.iter().map(|s| s.as_slice()))
                                   .help(true)
                                   .version(Some(version()));
    docopt.decode().map_err(|e| {
        let code = if e.fatal() {1} else {0};
        CliError::from_error(CargoDocoptError { err: e }, code)
    })
}

fn json_from_stdin<T: Decodable>() -> CliResult<T> {
    let mut reader = io::stdin();
    let input = try!(reader.read_to_string().map_err(|_| {
        CliError::new("Standard in did not exist or was not UTF-8", 1)
    }));

    let json = try!(Json::from_str(input.as_slice()).map_err(|_| {
        CliError::new("Could not parse standard in as JSON", 1)
    }));
    let mut decoder = json::Decoder::new(json);

    Decodable::decode(&mut decoder).map_err(|_| {
        CliError::new("Could not process standard in as input", 1)
    })
}
<commit_msg>Auto merge of #1202 - alexcrichton:issue-1201, r=huonw<commit_after>#![deny(unused)]
#![allow(unstable)]
#![cfg_attr(test, deny(warnings))]

extern crate libc;
extern crate "rustc-serialize" as rustc_serialize;
extern crate regex;
extern crate term;
extern crate time;
#[macro_use] extern crate log;

extern crate curl;
extern crate docopt;
extern crate flate2;
extern crate git2;
extern crate glob;
extern crate semver;
extern crate tar;
extern crate toml;
extern crate url;
#[cfg(test)] extern crate hamcrest;

extern crate registry;

use std::error::Error;
use std::io::stdio::{stdout_raw, stderr_raw};
use std::io::{self, stdout, stderr};
use std::os;
use rustc_serialize::{Decodable, Encodable};
use rustc_serialize::json::{self, Json};
use docopt::Docopt;

use core::{Shell, MultiShell, ShellConfig};
use term::color::{BLACK, RED};

pub use util::{CargoError, CliError, CliResult, human, Config};

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

pub fn execute_main<T, U, V>(
                        exec: fn(T, U, &Config) -> CliResult<Option<V>>,
                        options_first: bool,
                        usage: &str)
    where V: Encodable, T: Decodable, U: Decodable
{
    process::<V, _>(|rest, shell| {
        call_main(exec, shell, usage, rest, options_first)
    });
}

pub fn call_main<T, U, V>(
            exec: fn(T, U, &Config) -> CliResult<Option<V>>,
            shell: &Config,
            usage: &str,
            args: &[String],
            options_first: bool) -> CliResult<Option<V>>
    where V: Encodable, T: Decodable, U: Decodable
{
    let flags = try!(flags_from_args::<T>(usage, args, options_first));
    let json = try!(json_from_stdin::<U>());

    exec(flags, json, shell)
}

pub fn execute_main_without_stdin<T, V>(
                                      exec: fn(T, &Config) -> CliResult<Option<V>>,
                                      options_first: bool,
                                      usage: &str)
    where V: Encodable, T: Decodable
{
    process::<V, _>(|rest, shell| {
        call_main_without_stdin(exec, shell, usage, rest, options_first)
    });
}

pub fn call_main_without_stdin<T, V>(
            exec: fn(T, &Config) -> CliResult<Option<V>>,
            shell: &Config,
            usage: &str,
            args: &[String],
            options_first: bool) -> CliResult<Option<V>>
    where V: Encodable, T: Decodable
{
    let flags = try!(flags_from_args::<T>(usage, args, options_first));
    exec(flags, shell)
}

fn process<V, F>(mut callback: F)
    where F: FnMut(&[String], &Config) -> CliResult<Option<V>>,
          V: Encodable
{
    let mut shell = shell(true);
    process_executed({
        match Config::new(&mut shell) {
            Ok(cfg) => callback(os::args().as_slice(), &cfg),
            Err(e) => Err(CliError::from_boxed(e, 101)),
        }
    }, &mut shell)
}

pub fn process_executed<T>(result: CliResult<Option<T>>, shell: &mut MultiShell)
    where T: Encodable
{
    match result {
        Err(e) => handle_error(e, shell),
        Ok(Some(encodable)) => {
            let encoded = json::encode(&encodable);
            println!("{}", encoded);
        }
        _ => {}
    }
}

pub fn shell(verbose: bool) -> MultiShell {
    let tty = stderr_raw().isatty();
    let stderr = Box::new(stderr()) as Box<Writer + Send>;

    let config = ShellConfig { color: true, verbose: verbose, tty: tty };
    let err = Shell::create(stderr, config);

    let tty = stdout_raw().isatty();
    let stdout = Box::new(stdout()) as Box<Writer + Send>;

    let config = ShellConfig { color: true, verbose: verbose, tty: tty };
    let out = Shell::create(stdout, config);

    MultiShell::new(out, err, verbose)
}

// `output` print variant error strings to either stderr or stdout.
// For fatal errors, print to stderr;
// and for others, e.g. docopt version info, print to stdout.
fn output(caption: Option<&str>, detail: Option<String>,
          shell: &mut MultiShell, fatal: bool) {
    let std_shell = if fatal {shell.err()} else {shell.out()};
    if let Some(caption) = caption {
        let color = if fatal {RED} else {BLACK};
        let _ = std_shell.say(caption, color);
    }
    if let Some(detail) = detail {
        let _ = std_shell.say(detail, BLACK); // always black
    }
}

pub fn handle_error(err: CliError, shell: &mut MultiShell) {
    log!(4, "handle_error; err={:?}", err);

    let CliError { error, exit_code, unknown } = err;
    let fatal = exit_code != 0; // exit_code == 0 is non-fatal error

    let desc = error.description();
    let hide_desc = unknown && !shell.get_verbose();
    if hide_desc {
        output(Some("An unknown error occurred"), None, shell, fatal);
    } else if desc.len() > 0 {
        output(Some(desc), None, shell, fatal);
    }
    if shell.get_verbose() {
        output(None, error.detail(), shell, fatal);
    }
    if !handle_cause(&*error, shell) || (hide_desc && !desc.is_empty()) {
        let _ = shell.err().say("\nTo learn more, run the command again \
                                 with --verbose.".to_string(), BLACK);
    }

    std::os::set_exit_status(exit_code as isize);
}

fn handle_cause(mut cargo_err: &CargoError, shell: &mut MultiShell) -> bool {
    let verbose = shell.get_verbose();
    let mut err;
    loop {
        cargo_err = match cargo_err.cargo_cause() {
            Some(cause) => cause,
            None => { err = cargo_err.cause(); break }
        };
        if !verbose && !cargo_err.is_human() { return false }
        print(cargo_err.description(), cargo_err.detail(), shell);
    }
    loop {
        let cause = match err { Some(err) => err, None => return true };
        if !verbose { return false }
        print(cause.description(), cause.detail(), shell);
        err = cause.cause();
    }

    fn print(desc: &str, detail: Option<String>, shell: &mut MultiShell) {
        let _ = shell.err().say("\nCaused by:", BLACK);
        let _ = shell.err().say(format!("  {}", desc), BLACK);
        if shell.get_verbose() {
            if let Some(detail) = detail {
                let _ = shell.err().say(detail, BLACK);
            }
        }
    }
}

pub fn version() -> String {
    format!("cargo {}", match option_env!("CFG_VERSION") {
        Some(s) => s.to_string(),
        None => format!("{}.{}.{}{}",
                        env!("CARGO_PKG_VERSION_MAJOR"),
                        env!("CARGO_PKG_VERSION_MINOR"),
                        env!("CARGO_PKG_VERSION_PATCH"),
                        option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""))
    })
}

fn flags_from_args<'a, T>(usage: &str, args: &[String],
                          options_first: bool) -> CliResult<T>
    where T: Decodable
{
    let docopt = Docopt::new(usage).unwrap()
                                   .options_first(options_first)
                                   .argv(args.iter().map(|s| s.as_slice()))
                                   .help(true)
                                   .version(Some(version()));
    docopt.decode().map_err(|e| {
        let code = if e.fatal() {1} else {0};
        let desc = match e {
            docopt::Error::WithProgramUsage(_, s) => s,
            ref e if e.fatal() => e.description().to_string(),
            e => e.to_string(),
        };
        CliError::from_error(human(desc), code)
    })
}

fn json_from_stdin<T: Decodable>() -> CliResult<T> {
    let mut reader = io::stdin();
    let input = try!(reader.read_to_string().map_err(|_| {
        CliError::new("Standard in did not exist or was not UTF-8", 1)
    }));

    let json = try!(Json::from_str(input.as_slice()).map_err(|_| {
        CliError::new("Could not parse standard in as JSON", 1)
    }));
    let mut decoder = json::Decoder::new(json);

    Decodable::decode(&mut decoder).map_err(|_| {
        CliError::new("Could not process standard in as input", 1)
    })
}
<|endoftext|>


<commit_before>extern crate emu;
extern crate spc;
extern crate snes_apu;

use std::iter;
use std::env;
use std::io::{Result, Error, ErrorKind, Write, stdout, stdin};
use std::thread;
use std::sync::mpsc::{channel, Sender, Receiver};

use emu::audio_driver::AudioDriver;
use emu::audio_driver_factory;

use spc::spc::{Spc, Emulator};
use snes_apu::apu::Apu;
use snes_apu::dsp::dsp::{SAMPLE_RATE, BUFFER_LEN};

fn main() {
    if let Err(e) = play_spc_files() {
        println!("ERROR: {}", e);
        std::process::exit(1);
    }
}

fn play_spc_files() -> Result<()> {
    for file_name in try!(get_file_names()) {
        try!(play_spc_file(&file_name));
    }
    Ok(())
}

fn get_file_names() -> Result<iter::Skip<env::Args>> {
    let args = env::args();
    match args.len() {
        1 => Err(Error::new(ErrorKind::Other, "No file(s) specified")),
        _ => Ok(args.skip(1))
    }
}

struct SpcEndState {
    sample_pos: i32,
    fade_out_sample: i32,
    end_sample: i32,
    is_done_send: Sender<()>
}

fn play_spc_file(file_name: &String) -> Result<()> {
    let spc = try!(Spc::load(file_name));

    println!("SPC: {}", file_name);
    println!(" Version Minor: {}", spc.version_minor);
    println!(" PC: {}", spc.pc);
    println!(" A: {}", spc.a);
    println!(" X: {}", spc.x);
    println!(" Y: {}", spc.y);
    println!(" PSW: {}", spc.psw);
    println!(" SP: {}", spc.sp);

    if let Some(ref id666_tag) = spc.id666_tag {
        println!(" ID666 tag present:");
        println!("  Song title: {}", id666_tag.song_title);
        println!("  Game title: {}", id666_tag.game_title);
        println!("  Dumper name: {}", id666_tag.dumper_name);
        println!("  Comments: {}", id666_tag.comments);
        println!("  Date dumped (MM/DD/YYYY): {}", id666_tag.date_dumped);
        println!("  Seconds to play before fading out: {}", id666_tag.seconds_to_play_before_fading_out);
        println!("  Fade out length: {}ms", id666_tag.fade_out_length);
        println!("  Artist name: {}", id666_tag.artist_name);
        println!("  Default channel disables: {}", id666_tag.default_channel_disables);
        println!("  Dumping emulator: {}", match id666_tag.dumping_emulator {
            Emulator::Unknown => "Unknown",
            Emulator::ZSnes => "ZSnes",
            Emulator::Snes9x => "Snes9x"
        });
    } else {
        println!(" No ID666 tag present.");
    };

    let mut apu = Apu::new();
    apu.set_state(&spc);
    // Most SPC's have crap in the echo buffer on startup, so while it's not technically correct, we'll clear that.
    // The example for blargg's APU emulator (which is known to be the most accurate there is) also does this, so I
    //  think we're OK to do it too :)
    apu.clear_echo_buffer();

    let (is_done_send, is_done_recv) = channel();

    let mut driver = audio_driver_factory::create_default();
    driver.set_sample_rate(SAMPLE_RATE as i32);
    let mut left = Box::new([0; BUFFER_LEN]);
    let mut right = Box::new([0; BUFFER_LEN]);
    let mut end_state = if let Some(ref id666_tag) = spc.id666_tag {
        let fade_out_sample = id666_tag.seconds_to_play_before_fading_out * (SAMPLE_RATE as i32);
        let end_sample = fade_out_sample + id666_tag.fade_out_length * (SAMPLE_RATE as i32) / 1000;
        Some(SpcEndState {
            sample_pos: 0,
            fade_out_sample: fade_out_sample,
            end_sample: end_sample,
            is_done_send: is_done_send.clone()
        })
    } else {
        None
    };
    driver.set_render_callback(Some(Box::new(move |buffer, num_frames| {
        apu.render(&mut *left, &mut *right, num_frames as i32);
        match end_state {
            Some(ref mut state) => {
                for i in 0..num_frames {
                    let j = i * 2;
                    let sample_index = state.sample_pos + (i as i32);
                    let f = if sample_index >= state.end_sample {
                        0.0
                    } else if sample_index >= state.fade_out_sample {
                        1.0 - ((sample_index - state.fade_out_sample) as f32) / ((state.end_sample - state.fade_out_sample) as f32)
                    } else {
                        1.0
                    };
                    buffer[j + 0] = left[i] as f32 * f / 32768.0;
                    buffer[j + 1] = right[i] as f32 * f / 32768.0;
                }
                state.sample_pos += num_frames as i32;
                if state.sample_pos >= state.end_sample {
                    state.is_done_send.send(()).unwrap();
                }
            },
            _ => {
                for i in 0..num_frames {
                    let j = i * 2;
                    buffer[j + 0] = left[i] as f32 / 32768.0;
                    buffer[j + 1] = right[i] as f32 / 32768.0;
                }
            }
        }
    })));

    wait_for_key_press_with_busy_icon(is_done_send, is_done_recv)
}

fn wait_for_key_press_with_busy_icon(is_done_send: Sender<()>, is_done_recv: Receiver<()>) -> Result<()> {
    thread::spawn(move || {
        let mut s = String::new();
        stdin().read_line(&mut s).unwrap();
        is_done_send.send(()).unwrap();
    });

    println!("Return stops song.");
    let chars = ['-', '/', '|', '\\'];
    let mut char_index = 0;
    loop {
        if let Ok(()) = is_done_recv.try_recv() {
            break;
        }

        print!("\r[{}]", chars[char_index]);
        stdout().flush().unwrap();
        char_index = (char_index + 1) % chars.len();

        thread::sleep_ms(5);
    }
    print!("\r   \r");

    Ok(())
}
<commit_msg>Refactored example<commit_after>extern crate emu;
extern crate spc;
extern crate snes_apu;

use std::iter;
use std::env;
use std::io::{Result, Error, ErrorKind, Write, stdout, stdin};
use std::thread;
use std::sync::mpsc::{channel, Sender, Receiver};

use emu::audio_driver::AudioDriver;
use emu::audio_driver_factory;

use spc::spc::{Spc, Emulator};
use snes_apu::apu::Apu;
use snes_apu::dsp::dsp::{SAMPLE_RATE, BUFFER_LEN};

fn main() {
    if let Err(e) = play_spc_files() {
        println!("ERROR: {}", e);
        std::process::exit(1);
    }
}

fn play_spc_files() -> Result<()> {
    for file_name in try!(get_file_names()) {
        try!(play_spc_file(&file_name));
    }
    Ok(())
}

fn get_file_names() -> Result<iter::Skip<env::Args>> {
    let args = env::args();
    match args.len() {
        1 => Err(Error::new(ErrorKind::Other, "No file(s) specified")),
        _ => Ok(args.skip(1))
    }
}

struct SpcEndState {
    sample_pos: i32,
    fade_out_sample: i32,
    end_sample: i32,
    is_done_send: Sender<()>
}

fn play_spc_file(file_name: &String) -> Result<()> {
    let spc = try!(Spc::load(file_name));

    print_spc_file_info(file_name, &spc);

    let mut apu = Apu::new();
    apu.set_state(&spc);
    // Most SPC's have crap in the echo buffer on startup, so while it's not technically correct, we'll clear that.
    // The example for blargg's APU emulator (which is known to be the most accurate there is) also does this, so I
    //  think we're OK to do it too :)
    apu.clear_echo_buffer();

    let (is_done_send, is_done_recv) = channel();

    let mut driver = audio_driver_factory::create_default();
    driver.set_sample_rate(SAMPLE_RATE as i32);
    let mut left = Box::new([0; BUFFER_LEN]);
    let mut right = Box::new([0; BUFFER_LEN]);

    let mut end_state = if let Some(ref id666_tag) = spc.id666_tag {
        let fade_out_sample = id666_tag.seconds_to_play_before_fading_out * (SAMPLE_RATE as i32);
        let end_sample = fade_out_sample + id666_tag.fade_out_length * (SAMPLE_RATE as i32) / 1000;
        Some(SpcEndState {
            sample_pos: 0,
            fade_out_sample: fade_out_sample,
            end_sample: end_sample,
            is_done_send: is_done_send.clone()
        })
    } else {
        None
    };

    driver.set_render_callback(Some(Box::new(move |buffer, num_frames| {
        apu.render(&mut *left, &mut *right, num_frames as i32);
        match end_state {
            Some(ref mut state) => {
                for i in 0..num_frames {
                    let j = i * 2;
                    let sample_index = state.sample_pos + (i as i32);
                    let f = if sample_index >= state.end_sample {
                        0.0
                    } else if sample_index >= state.fade_out_sample {
                        1.0 - ((sample_index - state.fade_out_sample) as f32) / ((state.end_sample - state.fade_out_sample) as f32)
                    } else {
                        1.0
                    };
                    buffer[j + 0] = left[i] as f32 * f / 32768.0;
                    buffer[j + 1] = right[i] as f32 * f / 32768.0;
                }
                state.sample_pos += num_frames as i32;
                if state.sample_pos >= state.end_sample {
                    state.is_done_send.send(()).ok();
                }
            },
            _ => {
                for i in 0..num_frames {
                    let j = i * 2;
                    buffer[j + 0] = left[i] as f32 / 32768.0;
                    buffer[j + 1] = right[i] as f32 / 32768.0;
                }
            }
        }
    })));

    wait_for_key_press_with_busy_icon(is_done_send, is_done_recv)
}

fn print_spc_file_info(file_name: &String, spc: &Spc) {
    println!("SPC: {}", file_name);
    println!(" Version Minor: {}", spc.version_minor);
    println!(" PC: {}", spc.pc);
    println!(" A: {}", spc.a);
    println!(" X: {}", spc.x);
    println!(" Y: {}", spc.y);
    println!(" PSW: {}", spc.psw);
    println!(" SP: {}", spc.sp);

    if let Some(ref id666_tag) = spc.id666_tag {
        println!(" ID666 tag present:");
        println!("  Song title: {}", id666_tag.song_title);
        println!("  Game title: {}", id666_tag.game_title);
        println!("  Dumper name: {}", id666_tag.dumper_name);
        println!("  Comments: {}", id666_tag.comments);
        println!("  Date dumped (MM/DD/YYYY): {}", id666_tag.date_dumped);
        println!("  Seconds to play before fading out: {}", id666_tag.seconds_to_play_before_fading_out);
        println!("  Fade out length: {}ms", id666_tag.fade_out_length);
        println!("  Artist name: {}", id666_tag.artist_name);
        println!("  Default channel disables: {}", id666_tag.default_channel_disables);
        println!("  Dumping emulator: {}", match id666_tag.dumping_emulator {
            Emulator::Unknown => "Unknown",
            Emulator::ZSnes => "ZSnes",
            Emulator::Snes9x => "Snes9x"
        });
    } else {
        println!(" No ID666 tag present.");
    };
}

fn wait_for_key_press_with_busy_icon(is_done_send: Sender<()>, is_done_recv: Receiver<()>) -> Result<()> {
    thread::spawn(move || {
        let mut s = String::new();
        stdin().read_line(&mut s).ok();
        is_done_send.send(()).ok();
    });

    println!("Return stops song.");
    let chars = ['-', '/', '|', '\\'];
    let mut char_index = 0;
    loop {
        if let Ok(()) = is_done_recv.try_recv() {
            break;
        }

        print!("\r[{}]", chars[char_index]);
        stdout().flush().ok();
        char_index = (char_index + 1) % chars.len();

        thread::sleep_ms(5);
    }
    print!("\r   \r");

    Ok(())
}
<|endoftext|>


<commit_before>use ::std::io::Write;

use rustler::{NifEnv, NifTerm, NifEncoder, NifResult, NifError};
use rustler::types::binary::{ NifBinary, OwnedNifBinary };

pub fn make_shorter_subbinary<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let binary: NifBinary = try!(args[0].decode());
    let length: usize = binary.as_slice().len();
    Ok(try!(binary.make_subbinary(1, length-2)).encode(env))
}

pub fn parse_integer<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let str_num: &str = args[0].decode()?;
    let num: i64 = match ::std::str::FromStr::from_str(str_num) {
        Ok(num) => num,
        Err(_) => return Err(NifError::BadArg),
    };
    Ok(num.encode(env))
}

pub fn binary_new<'a>(env: NifEnv<'a>, _args: &Vec<NifTerm<'a>>) -> NifResult<NifTerm<'a>> {
    let mut binary = OwnedNifBinary::new(4).unwrap();
    binary.as_mut_slice().write(&[1, 2, 3, 4]).unwrap();
    Ok(binary.release(env).encode(env))
}

pub fn unowned_to_owned<'a>(env: NifEnv<'a>, args: &Vec<NifTerm<'a>>) -> NifResult<NifTerm<'a>> {
    let in_binary: NifBinary = args[0].decode()?;
    let mut copied = in_binary.to_owned().unwrap();
    copied.as_mut_slice()[0] = 1;
    Ok(copied.release(env).encode(env))
}

pub fn realloc_shrink<'a>(env: NifEnv<'a>, _args: &Vec<NifTerm<'a>>) -> NifResult<NifTerm<'a>> {
    let mut binary = OwnedNifBinary::new(8).unwrap();
    binary.as_mut_slice().write(&[1, 2, 3, 4, 5, 6, 7, 8]).unwrap();
    if !binary.realloc(4) {
        panic!("Realloc failed");
    }
    Ok(binary.release(env).encode(env))
}

pub fn realloc_grow<'a>(env: NifEnv<'a>, _args: &Vec<NifTerm<'a>>) -> NifResult<NifTerm<'a>> {
    let mut binary = OwnedNifBinary::new(4).unwrap();
    binary.as_mut_slice().write(&[1, 2, 3, 4]).unwrap();
    binary.realloc_or_copy(5);
    binary.as_mut_slice()[4] = 5;
    Ok(binary.release(env).encode(env))
}

// OwnedNifBinary::new
// OwnedNifBinary::from_unowned
// OwnedNifBinary::realloc
// OwnedNifBinary::realloc_or_copy
<commit_msg>fix tests<commit_after>use ::std::io::Write;

use rustler::{NifEnv, NifTerm, NifEncoder, NifResult, NifError};
use rustler::types::binary::{ NifBinary, OwnedNifBinary };

pub fn make_shorter_subbinary<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let binary: NifBinary = try!(args[0].decode());
    let length: usize = binary.as_slice().len();
    Ok(try!(binary.make_subbinary(1, length-2)).encode(env))
}

pub fn parse_integer<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let str_num: &str = args[0].decode()?;
    let num: i64 = match ::std::str::FromStr::from_str(str_num) {
        Ok(num) => num,
        Err(_) => return Err(NifError::BadArg),
    };
    Ok(num.encode(env))
}

pub fn binary_new<'a>(env: NifEnv<'a>, _args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let mut binary = OwnedNifBinary::new(4).unwrap();
    binary.as_mut_slice().write(&[1, 2, 3, 4]).unwrap();
    Ok(binary.release(env).encode(env))
}

pub fn unowned_to_owned<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let in_binary: NifBinary = args[0].decode()?;
    let mut copied = in_binary.to_owned().unwrap();
    copied.as_mut_slice()[0] = 1;
    Ok(copied.release(env).encode(env))
}

pub fn realloc_shrink<'a>(env: NifEnv<'a>, _args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let mut binary = OwnedNifBinary::new(8).unwrap();
    binary.as_mut_slice().write(&[1, 2, 3, 4, 5, 6, 7, 8]).unwrap();
    if !binary.realloc(4) {
        panic!("Realloc failed");
    }
    Ok(binary.release(env).encode(env))
}

pub fn realloc_grow<'a>(env: NifEnv<'a>, _args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
    let mut binary = OwnedNifBinary::new(4).unwrap();
    binary.as_mut_slice().write(&[1, 2, 3, 4]).unwrap();
    binary.realloc_or_copy(5);
    binary.as_mut_slice()[4] = 5;
    Ok(binary.release(env).encode(env))
}

// OwnedNifBinary::new
// OwnedNifBinary::from_unowned
// OwnedNifBinary::realloc
// OwnedNifBinary::realloc_or_copy
<|endoftext|>


<commit_before>use alloc::boxed::Box;
use core::fmt;
use core::marker::PhantomData;
use core::mem;
use core::ptr;

/// Number of words a piece of `Data` can hold.
///
/// Three words should be enough for the majority of cases. For example, you can fit inside it the
/// function pointer together with a fat pointer representing an object that needs to be destroyed.
const DATA_WORDS: usize = 3;

/// Some space to keep a `FnOnce()` object on the stack.
type Data = [usize; DATA_WORDS];

/// A `FnOnce()` that is stored inline if small, or otherwise boxed on the heap.
///
/// This is a handy way of keeping an unsized `FnOnce()` within a sized structure.
pub struct Deferred {
    call: unsafe fn(*mut u8),
    data: Data,
    _marker: PhantomData<*mut ()>, // !Send + !Sync
}

impl fmt::Debug for Deferred {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        f.pad("Deferred { .. }")
    }
}

impl Deferred {
    /// Constructs a new `Deferred` from a `FnOnce()`.
    pub fn new<F: FnOnce()>(f: F) -> Self {
        let size = mem::size_of::<F>();
        let align = mem::align_of::<F>();

        unsafe {
            if size <= mem::size_of::<Data>() && align <= mem::align_of::<Data>() {
                // TODO(taiki-e): when the minimum supported Rust version is bumped to 1.36+,
                // replace this with `mem::MaybeUninit`.
                #[allow(deprecated)]
                let mut data: Data = mem::uninitialized();
                ptr::write(&mut data as *mut Data as *mut F, f);

                unsafe fn call<F: FnOnce()>(raw: *mut u8) {
                    let f: F = ptr::read(raw as *mut F);
                    f();
                }

                Deferred {
                    call: call::<F>,
                    data,
                    _marker: PhantomData,
                }
            } else {
                let b: Box<F> = Box::new(f);
                // TODO(taiki-e): when the minimum supported Rust version is bumped to 1.36+,
                // replace this with `mem::MaybeUninit`.
                #[allow(deprecated)]
                let mut data: Data = mem::uninitialized();
                ptr::write(&mut data as *mut Data as *mut Box<F>, b);

                unsafe fn call<F: FnOnce()>(raw: *mut u8) {
                    let b: Box<F> = ptr::read(raw as *mut Box<F>);
                    (*b)();
                }

                Deferred {
                    call: call::<F>,
                    data,
                    _marker: PhantomData,
                }
            }
        }
    }

    /// Calls the function.
    #[inline]
    pub fn call(mut self) {
        let call = self.call;
        unsafe { call(&mut self.data as *mut Data as *mut u8) };
    }
}

#[cfg(test)]
mod tests {
    use super::Deferred;
    use std::cell::Cell;

    #[test]
    fn on_stack() {
        let fired = &Cell::new(false);
        let a = [0usize; 1];

        let d = Deferred::new(move || {
            drop(a);
            fired.set(true);
        });

        assert!(!fired.get());
        d.call();
        assert!(fired.get());
    }

    #[test]
    fn on_heap() {
        let fired = &Cell::new(false);
        let a = [0usize; 10];

        let d = Deferred::new(move || {
            drop(a);
            fired.set(true);
        });

        assert!(!fired.get());
        d.call();
        assert!(fired.get());
    }

    #[test]
    fn string() {
        let a = "hello".to_string();
        let d = Deferred::new(move || assert_eq!(a, "hello"));
        d.call();
    }

    #[test]
    fn boxed_slice_i32() {
        let a: Box<[i32]> = vec![2, 3, 5, 7].into_boxed_slice();
        let d = Deferred::new(move || assert_eq!(*a, [2, 3, 5, 7]));
        d.call();
    }

    #[test]
    fn long_slice_usize() {
        let a: [usize; 5] = [2, 3, 5, 7, 11];
        let d = Deferred::new(move || assert_eq!(a, [2, 3, 5, 7, 11]));
        d.call();
    }
}
<commit_msg>epoch: Fix fixme in deferred.rs (mem::uninitialized -> MaybeUninit)<commit_after>use alloc::boxed::Box;
use core::fmt;
use core::marker::PhantomData;
use core::mem::{self, MaybeUninit};
use core::ptr;

/// Number of words a piece of `Data` can hold.
///
/// Three words should be enough for the majority of cases. For example, you can fit inside it the
/// function pointer together with a fat pointer representing an object that needs to be destroyed.
const DATA_WORDS: usize = 3;

/// Some space to keep a `FnOnce()` object on the stack.
type Data = [usize; DATA_WORDS];

/// A `FnOnce()` that is stored inline if small, or otherwise boxed on the heap.
///
/// This is a handy way of keeping an unsized `FnOnce()` within a sized structure.
pub struct Deferred {
    call: unsafe fn(*mut u8),
    data: Data,
    _marker: PhantomData<*mut ()>, // !Send + !Sync
}

impl fmt::Debug for Deferred {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        f.pad("Deferred { .. }")
    }
}

impl Deferred {
    /// Constructs a new `Deferred` from a `FnOnce()`.
    pub fn new<F: FnOnce()>(f: F) -> Self {
        let size = mem::size_of::<F>();
        let align = mem::align_of::<F>();

        unsafe {
            if size <= mem::size_of::<Data>() && align <= mem::align_of::<Data>() {
                let mut data = MaybeUninit::<Data>::uninit();
                ptr::write(data.as_mut_ptr() as *mut F, f);

                unsafe fn call<F: FnOnce()>(raw: *mut u8) {
                    let f: F = ptr::read(raw as *mut F);
                    f();
                }

                Deferred {
                    call: call::<F>,
                    data: data.assume_init(),
                    _marker: PhantomData,
                }
            } else {
                let b: Box<F> = Box::new(f);
                let mut data = MaybeUninit::<Data>::uninit();
                ptr::write(data.as_mut_ptr() as *mut Box<F>, b);

                unsafe fn call<F: FnOnce()>(raw: *mut u8) {
                    let b: Box<F> = ptr::read(raw as *mut Box<F>);
                    (*b)();
                }

                Deferred {
                    call: call::<F>,
                    data: data.assume_init(),
                    _marker: PhantomData,
                }
            }
        }
    }

    /// Calls the function.
    #[inline]
    pub fn call(mut self) {
        let call = self.call;
        unsafe { call(&mut self.data as *mut Data as *mut u8) };
    }
}

#[cfg(test)]
mod tests {
    use super::Deferred;
    use std::cell::Cell;

    #[test]
    fn on_stack() {
        let fired = &Cell::new(false);
        let a = [0usize; 1];

        let d = Deferred::new(move || {
            drop(a);
            fired.set(true);
        });

        assert!(!fired.get());
        d.call();
        assert!(fired.get());
    }

    #[test]
    fn on_heap() {
        let fired = &Cell::new(false);
        let a = [0usize; 10];

        let d = Deferred::new(move || {
            drop(a);
            fired.set(true);
        });

        assert!(!fired.get());
        d.call();
        assert!(fired.get());
    }

    #[test]
    fn string() {
        let a = "hello".to_string();
        let d = Deferred::new(move || assert_eq!(a, "hello"));
        d.call();
    }

    #[test]
    fn boxed_slice_i32() {
        let a: Box<[i32]> = vec![2, 3, 5, 7].into_boxed_slice();
        let d = Deferred::new(move || assert_eq!(*a, [2, 3, 5, 7]));
        d.call();
    }

    #[test]
    fn long_slice_usize() {
        let a: [usize; 5] = [2, 3, 5, 7, 11];
        let d = Deferred::new(move || assert_eq!(a, [2, 3, 5, 7, 11]));
        d.call();
    }
}
<|endoftext|>


<commit_before>extern crate nalgebra;
extern crate num;

use nalgebra::Origin;
use std::error;
use std::error::Error;
use std::fmt;
use std::ops;

use IgnorableResult;
use math::Clamp;
use resource::ResourceId;
use super::geometry::*;
use super::space::*;

pub type NodeLink = Box<[Node; 8]>;

pub enum Node {
    Leaf(LeafNode),
    Branch(NodeLink, BranchNode),
}

impl Node {
    fn new() -> Self {
        Node::Leaf(LeafNode::new())
    }

    pub fn is_leaf(&self) -> bool {
        match *self {
            Node::Leaf(..) => true,
            _ => false,
        }
    }

    fn to_orphan<'a>(&'a self) -> (OrphanNode<'a>, Option<&'a NodeLink>) {
        match *self {
            Node::Leaf(ref leaf) => (OrphanNode::Leaf(leaf), None),
            Node::Branch(ref nodes, ref branch) => (OrphanNode::Branch(branch), Some(nodes)),
        }
    }

    fn to_orphan_mut<'a>(&'a mut self) -> (OrphanNodeMut<'a>, Option<&'a mut NodeLink>) {
        match *self {
            Node::Leaf(ref mut leaf) => (OrphanNodeMut::Leaf(leaf), None),
            Node::Branch(ref mut nodes, ref mut branch) => {
                (OrphanNodeMut::Branch(branch), Some(nodes))
            }
        }
    }

    fn join(&mut self) -> Result<(), JoinError> {
        if let Node::Branch(..) = *self {
            *self = Node::Leaf(LeafNode::new());
            Ok(())
        }
        else {
            Err(JoinError::AlreadyJoined)
        }
    }

    fn subdivide(&mut self) -> Result<(), SubdivideError> {
        if let Node::Leaf(..) = *self {
            *self = Node::Branch(Box::new([self.clone(),
                                           self.clone(),
                                           self.clone(),
                                           self.clone(),
                                           self.clone(),
                                           self.clone(),
                                           self.clone(),
                                           self.clone()]),
                                 BranchNode::new());
            Ok(())
        }
        else {
            Err(SubdivideError::AlreadySubdivided)
        }
    }
}

impl Clone for Node {
    fn clone(&self) -> Self {
        match *self {
            Node::Leaf(leaf) => Node::Leaf(leaf.clone()),
            Node::Branch(ref nodes, branch) => {
                Node::Branch(Box::new([nodes[0].clone(),
                                       nodes[1].clone(),
                                       nodes[2].clone(),
                                       nodes[3].clone(),
                                       nodes[4].clone(),
                                       nodes[5].clone(),
                                       nodes[6].clone(),
                                       nodes[7].clone()]),
                             branch.clone())
            }
        }
    }
}

pub enum OrphanNode<'a> {
    Leaf(&'a LeafNode),
    Branch(&'a BranchNode),
}

pub enum OrphanNodeMut<'a> {
    Leaf(&'a mut LeafNode),
    Branch(&'a mut BranchNode),
}

#[derive(Clone, Copy)]
pub struct LeafNode {
    pub geometry: Geometry,
    pub material: ResourceId,
}

impl LeafNode {
    fn new() -> Self {
        LeafNode {
            geometry: Geometry::full(),
            material: 0,
        }
    }
}

#[derive(Clone, Copy)]
pub struct BranchNode {}

impl BranchNode {
    fn new() -> Self {
        BranchNode {}
    }
}

pub struct Root {
    node: Box<Node>,
    partition: Partition,
}

impl Root {
    pub fn new(width: LogWidth) -> Self {
        Root {
            node: Box::new(Node::new()),
            partition: Partition::at_point(&Point3::origin(), width),
        }
    }

    pub fn to_cube(&self) -> Cube {
        Cube::new(&self.node, &self.partition, self.partition)
    }

    pub fn to_cube_mut(&mut self) -> CubeMut {
        CubeMut::new(&mut self.node, &self.partition, self.partition)
    }
}

impl Spatial for Root {
    fn partition(&self) -> &Partition {
        &self.partition
    }

    fn depth(&self) -> u8 {
        0
    }
}

#[derive(Clone)]
pub struct Cube<'a> {
    node: &'a Node,
    root: &'a Partition,
    partition: Partition,
}

impl<'a> Cube<'a> {
    fn new(node: &'a Node, root: &'a Partition, partition: Partition) -> Self {
        Cube {
            node: node,
            root: root,
            partition: partition,
        }
    }

    pub fn to_orphan(&self) -> OrphanCube {
        let (orphan, _) = self.node.to_orphan();
        OrphanCube::new(orphan, self.root, self.partition)
    }

    pub fn iter(&self) -> CubeIter {
        CubeIter::new(self.clone())
    }

    // TODO: Is this useful? `CubeIter` already yields fully linked `Cube`s.
    pub fn walk<F, R>(&'a self, f: &F)
        where F: Fn(Cube<'a>) -> R
    {
        for node in self.iter() {
            f(node);
        }
    }

    pub fn at_point(&self, point: &Point3, width: LogWidth) -> Self {
        let mut node = self.node;
        let mut depth = self.partition.width();

        // Clamp the inputs.
        let point = point.clamp(0, (exp(self.root.width())) - 1);
        let width = width.clamp(MIN_WIDTH, depth);

        while width < depth {
            match *node {
                Node::Branch(ref nodes, _) => {
                    depth = depth - 1;
                    node = &nodes[index_at_point(&point, depth)]
                }
                _ => break,
            }
        }
        Cube::new(node, self.root, Partition::at_point(&point, depth))
    }

    pub fn at_index(&self, index: usize) -> Option<Self> {
        match *self.node {
            Node::Branch(ref nodes, _) => {
                self.partition
                    .at_index(index)
                    .map(|partition| Cube::new(&nodes[index], self.root, partition))
            }
            _ => None,
        }
    }
}

impl<'a> ops::Deref for Cube<'a> {
    type Target = Node;

    fn deref(&self) -> &Self::Target {
        self.node
    }
}

impl<'a> From<CubeMut<'a>> for Cube<'a> {
    fn from(cube: CubeMut<'a>) -> Self {
        Cube::new(&*cube.node, cube.root, cube.partition)
    }
}

impl<'a> Spatial for Cube<'a> {
    fn partition(&self) -> &Partition {
        &self.partition
    }

    fn depth(&self) -> u8 {
        self.root.width() - self.partition.width()
    }
}

pub struct CubeIter<'a>(Vec<Cube<'a>>);

impl<'a> CubeIter<'a> {
    fn new(cube: Cube<'a>) -> Self {
        CubeIter(vec![cube])
    }
}

impl<'a> Iterator for CubeIter<'a> {
    type Item = Cube<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(cube) = self.0.pop() {
            match *cube.node {
                Node::Branch(ref nodes, _) => {
                    for (index, node) in nodes.iter().enumerate() {
                        self.0.push(Cube::new(node,
                                              cube.root,
                                              cube.partition().at_index(index).unwrap()));
                    }
                }
                _ => {}
            }
            Some(cube)
        }
        else {
            None
        }
    }
}

pub struct CubeMut<'a> {
    node: &'a mut Node,
    root: &'a Partition,
    partition: Partition,
}

impl<'a> CubeMut<'a> {
    fn new(node: &'a mut Node, root: &'a Partition, partition: Partition) -> Self {
        CubeMut {
            node: node,
            root: root,
            partition: partition,
        }
    }

    pub fn to_orphan(&mut self) -> OrphanCubeMut {
        let (orphan, _) = self.node.to_orphan_mut();
        OrphanCubeMut::new(orphan, self.root, self.partition)
    }

    pub fn iter(&mut self) -> CubeMutIter {
        CubeMutIter::new(self)
    }

    pub fn walk<F, R>(&mut self, f: &F)
        where F: Fn(&mut CubeMut) -> R
    {
        let mut cubes = vec![CubeMut::new(self.node, self.root, self.partition)];
        while let Some(mut cube) = cubes.pop() {
            f(&mut cube);
            let (_, nodes) = cube.node.to_orphan_mut();
            if let Some(nodes) = nodes {
                for (index, node) in nodes.iter_mut().enumerate() {
                    cubes.push(CubeMut::new(node,
                                            cube.root,
                                            cube.partition.at_index(index).unwrap()));
                }
            }
        }
    }

    pub fn at_point(&mut self, point: &Point3, width: LogWidth) -> CubeMut {
        let mut node: Option<&mut Node> = Some(self.node);
        let mut depth = self.partition.width();

        let point = point.clamp(0, (exp(self.root.width())) - 1);
        let width = width.clamp(MIN_WIDTH, depth);

        while width < depth {
            let taken = node.take().unwrap();
            match *taken {
                Node::Branch(ref mut nodes, _) => {
                    depth = depth - 1;
                    node = Some(&mut nodes[index_at_point(&point, depth)]);
                }
                _ => {
                    node = Some(taken);
                    break;
                }
            }
        }
        CubeMut::new(node.take().unwrap(),
                     self.root,
                     Partition::at_point(&point, depth))
    }

    pub fn at_index(&mut self, index: usize) -> Option<CubeMut> {
        match *self.node {
            Node::Branch(ref mut nodes, _) => {
                let root = self.root;
                self.partition
                    .at_index(index)
                    .map(move |partition| CubeMut::new(&mut nodes[index], root, partition))
            }
            _ => None,
        }
    }

    pub fn join(&mut self) -> Result<(), JoinError> {
        self.node.join()
    }

    pub fn subdivide(&mut self) -> Result<(), SubdivideError> {
        if self.partition().is_min_width() {
            Err(SubdivideError::LimitExceeded)
        }
        else {
            self.node.subdivide()
        }
    }

    pub fn subdivide_to_point(&mut self, point: &Point3, width: LogWidth) -> CubeMut {
        let width = width.clamp(MIN_WIDTH, MAX_WIDTH);
        let mut depth = width;
        let mut cube = Some(self.at_point(point, width));
        while cube.as_ref().unwrap().partition.width() > width {
            depth = depth - 1;
            let mut taken = cube.take().unwrap();
            taken.node.subdivide().ignore();
            if let Node::Branch(ref mut nodes, _) = *taken.node {
                let index = index_at_point(point, depth);
                cube = Some(CubeMut::new(&mut nodes[index],
                                         taken.root,
                                         taken.partition.at_index(index).unwrap()));
            }
        }
        cube.take().unwrap()
    }
}

impl<'a> ops::Deref for CubeMut<'a> {
    type Target = Node;

    fn deref(&self) -> &Self::Target {
        &*self.node
    }
}

impl<'a> ops::DerefMut for CubeMut<'a> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.node
    }
}

impl<'a> Spatial for CubeMut<'a> {
    fn partition(&self) -> &Partition {
        &self.partition
    }

    fn depth(&self) -> u8 {
        self.root.width() - self.partition.width()
    }
}

pub struct CubeMutIter<'a>(Vec<CubeMut<'a>>);

impl<'a> CubeMutIter<'a> {
    fn new(cube: &'a mut CubeMut) -> Self {
        CubeMutIter(vec![CubeMut::new(cube.node, cube.root, cube.partition)])
    }
}

impl<'a> Iterator for CubeMutIter<'a> {
    type Item = OrphanCubeMut<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(cube) = self.0.pop() {
            let (orphan, nodes) = cube.node.to_orphan_mut();
            if let Some(nodes) = nodes {
                for (index, node) in nodes.iter_mut().enumerate() {
                    self.0.push(CubeMut::new(node,
                                             cube.root,
                                             cube.partition.at_index(index).unwrap()));
                }
            }
            Some(OrphanCubeMut::new(orphan, cube.root, cube.partition))
        }
        else {
            None
        }
    }
}

pub struct OrphanCube<'a> {
    node: OrphanNode<'a>,
    root: &'a Partition,
    partition: Partition,
}

impl<'a> OrphanCube<'a> {
    fn new(node: OrphanNode<'a>, root: &'a Partition, partition: Partition) -> Self {
        OrphanCube {
            node: node,
            root: root,
            partition: partition,
        }
    }
}

impl<'a> ops::Deref for OrphanCube<'a> {
    type Target = OrphanNode<'a>;

    fn deref(&self) -> &Self::Target {
        &self.node
    }
}

impl<'a> Spatial for OrphanCube<'a> {
    fn partition(&self) -> &Partition {
        &self.partition
    }

    fn depth(&self) -> u8 {
        self.root.width() - self.partition.width()
    }
}

pub struct OrphanCubeMut<'a> {
    node: OrphanNodeMut<'a>,
    root: &'a Partition,
    partition: Partition,
}

impl<'a> OrphanCubeMut<'a> {
    fn new(node: OrphanNodeMut<'a>, root: &'a Partition, partition: Partition) -> Self {
        OrphanCubeMut {
            node: node,
            root: root,
            partition: partition,
        }
    }
}

impl<'a> ops::Deref for OrphanCubeMut<'a> {
    type Target = OrphanNodeMut<'a>;

    fn deref(&self) -> &Self::Target {
        &self.node
    }
}

impl<'a> ops::DerefMut for OrphanCubeMut<'a> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.node
    }
}

impl<'a> Spatial for OrphanCubeMut<'a> {
    fn partition(&self) -> &Partition {
        &self.partition
    }

    fn depth(&self) -> u8 {
        self.root.width() - self.partition.width()
    }
}

#[derive(Debug)]
pub enum JoinError {
    AlreadyJoined,
}

impl fmt::Display for JoinError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", self.description())
    }
}

impl error::Error for JoinError {
    fn description(&self) -> &str {
        match *self {
            JoinError::AlreadyJoined => "attempted to join leaf",
        }
    }
}

#[derive(Debug)]
pub enum SubdivideError {
    LimitExceeded,
    AlreadySubdivided,
}

impl fmt::Display for SubdivideError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", self.description())
    }
}

impl error::Error for SubdivideError {
    fn description(&self) -> &str {
        match *self {
            SubdivideError::LimitExceeded => "minimum width limit exceeded",
            SubdivideError::AlreadySubdivided => "attempted to subdivide branch",
        }
    }
}

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

    #[test]
    fn test_cube_subdivide_to_point() {
        let point = Point3::origin();
        let width = MIN_WIDTH;
        let mut root = Root::new(MAX_WIDTH);

        root.to_cube_mut().subdivide_to_point(&point, width);
        assert!(root.to_cube().at_point(&point, width).partition().width() == width);
    }
}
<commit_msg>Fix `Cube` lifetimes.<commit_after>extern crate nalgebra;
extern crate num;

use nalgebra::Origin;
use std::error;
use std::error::Error;
use std::fmt;
use std::ops;

use IgnorableResult;
use math::Clamp;
use resource::ResourceId;
use super::geometry::*;
use super::space::*;

pub type NodeLink = Box<[Node; 8]>;

pub enum Node {
    Leaf(LeafNode),
    Branch(NodeLink, BranchNode),
}

impl Node {
    fn new() -> Self {
        Node::Leaf(LeafNode::new())
    }

    pub fn is_leaf(&self) -> bool {
        match *self {
            Node::Leaf(..) => true,
            _ => false,
        }
    }

    fn to_orphan<'a>(&'a self) -> (OrphanNode<'a>, Option<&'a NodeLink>) {
        match *self {
            Node::Leaf(ref leaf) => (OrphanNode::Leaf(leaf), None),
            Node::Branch(ref nodes, ref branch) => (OrphanNode::Branch(branch), Some(nodes)),
        }
    }

    fn to_orphan_mut<'a>(&'a mut self) -> (OrphanNodeMut<'a>, Option<&'a mut NodeLink>) {
        match *self {
            Node::Leaf(ref mut leaf) => (OrphanNodeMut::Leaf(leaf), None),
            Node::Branch(ref mut nodes, ref mut branch) => {
                (OrphanNodeMut::Branch(branch), Some(nodes))
            }
        }
    }

    fn join(&mut self) -> Result<(), JoinError> {
        if let Node::Branch(..) = *self {
            *self = Node::Leaf(LeafNode::new());
            Ok(())
        }
        else {
            Err(JoinError::AlreadyJoined)
        }
    }

    fn subdivide(&mut self) -> Result<(), SubdivideError> {
        if let Node::Leaf(..) = *self {
            *self = Node::Branch(Box::new([self.clone(),
                                           self.clone(),
                                           self.clone(),
                                           self.clone(),
                                           self.clone(),
                                           self.clone(),
                                           self.clone(),
                                           self.clone()]),
                                 BranchNode::new());
            Ok(())
        }
        else {
            Err(SubdivideError::AlreadySubdivided)
        }
    }
}

impl Clone for Node {
    fn clone(&self) -> Self {
        match *self {
            Node::Leaf(leaf) => Node::Leaf(leaf.clone()),
            Node::Branch(ref nodes, branch) => {
                Node::Branch(Box::new([nodes[0].clone(),
                                       nodes[1].clone(),
                                       nodes[2].clone(),
                                       nodes[3].clone(),
                                       nodes[4].clone(),
                                       nodes[5].clone(),
                                       nodes[6].clone(),
                                       nodes[7].clone()]),
                             branch.clone())
            }
        }
    }
}

pub enum OrphanNode<'a> {
    Leaf(&'a LeafNode),
    Branch(&'a BranchNode),
}

pub enum OrphanNodeMut<'a> {
    Leaf(&'a mut LeafNode),
    Branch(&'a mut BranchNode),
}

#[derive(Clone, Copy)]
pub struct LeafNode {
    pub geometry: Geometry,
    pub material: ResourceId,
}

impl LeafNode {
    fn new() -> Self {
        LeafNode {
            geometry: Geometry::full(),
            material: 0,
        }
    }
}

#[derive(Clone, Copy)]
pub struct BranchNode {}

impl BranchNode {
    fn new() -> Self {
        BranchNode {}
    }
}

pub struct Root {
    node: Box<Node>,
    partition: Partition,
}

impl Root {
    pub fn new(width: LogWidth) -> Self {
        Root {
            node: Box::new(Node::new()),
            partition: Partition::at_point(&Point3::origin(), width),
        }
    }

    pub fn to_cube(&self) -> Cube {
        Cube::new(&self.node, &self.partition, self.partition)
    }

    pub fn to_cube_mut(&mut self) -> CubeMut {
        CubeMut::new(&mut self.node, &self.partition, self.partition)
    }
}

impl Spatial for Root {
    fn partition(&self) -> &Partition {
        &self.partition
    }

    fn depth(&self) -> u8 {
        0
    }
}

#[derive(Clone)]
pub struct Cube<'a> {
    node: &'a Node,
    root: &'a Partition,
    partition: Partition,
}

impl<'a> Cube<'a> {
    fn new(node: &'a Node, root: &'a Partition, partition: Partition) -> Self {
        Cube {
            node: node,
            root: root,
            partition: partition,
        }
    }

    pub fn to_orphan(&self) -> OrphanCube {
        let (orphan, _) = self.node.to_orphan();
        OrphanCube::new(orphan, self.root, self.partition)
    }

    pub fn iter(&self) -> CubeIter {
        CubeIter::new(self.clone())
    }

    // TODO: Is this useful? `CubeIter` already yields fully linked `Cube`s.
    pub fn walk<F, R>(&self, f: &F)
        where F: Fn(&Cube) -> R
    {
        for node in self.iter() {
            f(&node);
        }
    }

    pub fn at_point(&self, point: &Point3, width: LogWidth) -> Cube {
        let mut node = self.node;
        let mut depth = self.partition.width();

        // Clamp the inputs.
        let point = point.clamp(0, (exp(self.root.width())) - 1);
        let width = width.clamp(MIN_WIDTH, depth);

        while width < depth {
            match *node {
                Node::Branch(ref nodes, _) => {
                    depth = depth - 1;
                    node = &nodes[index_at_point(&point, depth)]
                }
                _ => break,
            }
        }
        Cube::new(node, self.root, Partition::at_point(&point, depth))
    }

    pub fn at_index(&self, index: usize) -> Option<Cube> {
        match *self.node {
            Node::Branch(ref nodes, _) => {
                self.partition
                    .at_index(index)
                    .map(|partition| Cube::new(&nodes[index], self.root, partition))
            }
            _ => None,
        }
    }
}

impl<'a> ops::Deref for Cube<'a> {
    type Target = Node;

    fn deref(&self) -> &Self::Target {
        self.node
    }
}

impl<'a> From<CubeMut<'a>> for Cube<'a> {
    fn from(cube: CubeMut<'a>) -> Self {
        Cube::new(&*cube.node, cube.root, cube.partition)
    }
}

impl<'a> Spatial for Cube<'a> {
    fn partition(&self) -> &Partition {
        &self.partition
    }

    fn depth(&self) -> u8 {
        self.root.width() - self.partition.width()
    }
}

pub struct CubeIter<'a>(Vec<Cube<'a>>);

impl<'a> CubeIter<'a> {
    fn new(cube: Cube<'a>) -> Self {
        CubeIter(vec![cube])
    }
}

impl<'a> Iterator for CubeIter<'a> {
    type Item = Cube<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(cube) = self.0.pop() {
            match *cube.node {
                Node::Branch(ref nodes, _) => {
                    for (index, node) in nodes.iter().enumerate() {
                        self.0.push(Cube::new(node,
                                              cube.root,
                                              cube.partition().at_index(index).unwrap()));
                    }
                }
                _ => {}
            }
            Some(cube)
        }
        else {
            None
        }
    }
}

pub struct CubeMut<'a> {
    node: &'a mut Node,
    root: &'a Partition,
    partition: Partition,
}

impl<'a> CubeMut<'a> {
    fn new(node: &'a mut Node, root: &'a Partition, partition: Partition) -> Self {
        CubeMut {
            node: node,
            root: root,
            partition: partition,
        }
    }

    pub fn to_orphan(&mut self) -> OrphanCubeMut {
        let (orphan, _) = self.node.to_orphan_mut();
        OrphanCubeMut::new(orphan, self.root, self.partition)
    }

    pub fn iter(&mut self) -> CubeMutIter {
        CubeMutIter::new(self)
    }

    pub fn walk<F, R>(&mut self, f: &F)
        where F: Fn(&mut CubeMut) -> R
    {
        let mut cubes = vec![CubeMut::new(self.node, self.root, self.partition)];
        while let Some(mut cube) = cubes.pop() {
            f(&mut cube);
            let (_, nodes) = cube.node.to_orphan_mut();
            if let Some(nodes) = nodes {
                for (index, node) in nodes.iter_mut().enumerate() {
                    cubes.push(CubeMut::new(node,
                                            cube.root,
                                            cube.partition.at_index(index).unwrap()));
                }
            }
        }
    }

    pub fn at_point(&mut self, point: &Point3, width: LogWidth) -> CubeMut {
        let mut node: Option<&mut Node> = Some(self.node);
        let mut depth = self.partition.width();

        let point = point.clamp(0, (exp(self.root.width())) - 1);
        let width = width.clamp(MIN_WIDTH, depth);

        while width < depth {
            let taken = node.take().unwrap();
            match *taken {
                Node::Branch(ref mut nodes, _) => {
                    depth = depth - 1;
                    node = Some(&mut nodes[index_at_point(&point, depth)]);
                }
                _ => {
                    node = Some(taken);
                    break;
                }
            }
        }
        CubeMut::new(node.take().unwrap(),
                     self.root,
                     Partition::at_point(&point, depth))
    }

    pub fn at_index(&mut self, index: usize) -> Option<CubeMut> {
        match *self.node {
            Node::Branch(ref mut nodes, _) => {
                let root = self.root;
                self.partition
                    .at_index(index)
                    .map(move |partition| CubeMut::new(&mut nodes[index], root, partition))
            }
            _ => None,
        }
    }

    pub fn join(&mut self) -> Result<(), JoinError> {
        self.node.join()
    }

    pub fn subdivide(&mut self) -> Result<(), SubdivideError> {
        if self.partition().is_min_width() {
            Err(SubdivideError::LimitExceeded)
        }
        else {
            self.node.subdivide()
        }
    }

    pub fn subdivide_to_point(&mut self, point: &Point3, width: LogWidth) -> CubeMut {
        let width = width.clamp(MIN_WIDTH, MAX_WIDTH);
        let mut depth = width;
        let mut cube = Some(self.at_point(point, width));
        while cube.as_ref().unwrap().partition.width() > width {
            depth = depth - 1;
            let mut taken = cube.take().unwrap();
            taken.node.subdivide().ignore();
            if let Node::Branch(ref mut nodes, _) = *taken.node {
                let index = index_at_point(point, depth);
                cube = Some(CubeMut::new(&mut nodes[index],
                                         taken.root,
                                         taken.partition.at_index(index).unwrap()));
            }
        }
        cube.take().unwrap()
    }
}

impl<'a> ops::Deref for CubeMut<'a> {
    type Target = Node;

    fn deref(&self) -> &Self::Target {
        &*self.node
    }
}

impl<'a> ops::DerefMut for CubeMut<'a> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.node
    }
}

impl<'a> Spatial for CubeMut<'a> {
    fn partition(&self) -> &Partition {
        &self.partition
    }

    fn depth(&self) -> u8 {
        self.root.width() - self.partition.width()
    }
}

pub struct CubeMutIter<'a>(Vec<CubeMut<'a>>);

impl<'a> CubeMutIter<'a> {
    fn new(cube: &'a mut CubeMut) -> Self {
        CubeMutIter(vec![CubeMut::new(cube.node, cube.root, cube.partition)])
    }
}

impl<'a> Iterator for CubeMutIter<'a> {
    type Item = OrphanCubeMut<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(cube) = self.0.pop() {
            let (orphan, nodes) = cube.node.to_orphan_mut();
            if let Some(nodes) = nodes {
                for (index, node) in nodes.iter_mut().enumerate() {
                    self.0.push(CubeMut::new(node,
                                             cube.root,
                                             cube.partition.at_index(index).unwrap()));
                }
            }
            Some(OrphanCubeMut::new(orphan, cube.root, cube.partition))
        }
        else {
            None
        }
    }
}

pub struct OrphanCube<'a> {
    node: OrphanNode<'a>,
    root: &'a Partition,
    partition: Partition,
}

impl<'a> OrphanCube<'a> {
    fn new(node: OrphanNode<'a>, root: &'a Partition, partition: Partition) -> Self {
        OrphanCube {
            node: node,
            root: root,
            partition: partition,
        }
    }
}

impl<'a> ops::Deref for OrphanCube<'a> {
    type Target = OrphanNode<'a>;

    fn deref(&self) -> &Self::Target {
        &self.node
    }
}

impl<'a> Spatial for OrphanCube<'a> {
    fn partition(&self) -> &Partition {
        &self.partition
    }

    fn depth(&self) -> u8 {
        self.root.width() - self.partition.width()
    }
}

pub struct OrphanCubeMut<'a> {
    node: OrphanNodeMut<'a>,
    root: &'a Partition,
    partition: Partition,
}

impl<'a> OrphanCubeMut<'a> {
    fn new(node: OrphanNodeMut<'a>, root: &'a Partition, partition: Partition) -> Self {
        OrphanCubeMut {
            node: node,
            root: root,
            partition: partition,
        }
    }
}

impl<'a> ops::Deref for OrphanCubeMut<'a> {
    type Target = OrphanNodeMut<'a>;

    fn deref(&self) -> &Self::Target {
        &self.node
    }
}

impl<'a> ops::DerefMut for OrphanCubeMut<'a> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.node
    }
}

impl<'a> Spatial for OrphanCubeMut<'a> {
    fn partition(&self) -> &Partition {
        &self.partition
    }

    fn depth(&self) -> u8 {
        self.root.width() - self.partition.width()
    }
}

#[derive(Debug)]
pub enum JoinError {
    AlreadyJoined,
}

impl fmt::Display for JoinError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", self.description())
    }
}

impl error::Error for JoinError {
    fn description(&self) -> &str {
        match *self {
            JoinError::AlreadyJoined => "attempted to join leaf",
        }
    }
}

#[derive(Debug)]
pub enum SubdivideError {
    LimitExceeded,
    AlreadySubdivided,
}

impl fmt::Display for SubdivideError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", self.description())
    }
}

impl error::Error for SubdivideError {
    fn description(&self) -> &str {
        match *self {
            SubdivideError::LimitExceeded => "minimum width limit exceeded",
            SubdivideError::AlreadySubdivided => "attempted to subdivide branch",
        }
    }
}

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

    #[test]
    fn test_cube_subdivide_to_point() {
        let point = Point3::origin();
        let width = MIN_WIDTH;
        let mut root = Root::new(MAX_WIDTH);

        root.to_cube_mut().subdivide_to_point(&point, width);
        assert!(root.to_cube().at_point(&point, width).partition().width() == width);
    }
}
<|endoftext|>