<commit_before>#[macro_use]
extern crate serde_derive;
extern crate toml;
extern crate clap;
extern crate hyper;
extern crate hyper_native_tls;

mod gitignore;
mod cli;

use std::fs::{File, OpenOptions, create_dir, read_dir};
use std::io::{BufReader, Result, Error, ErrorKind};
use std::io::prelude::*;
use std::path::Path;
use std::process::{exit, Command};
use std::env;

#[derive(Deserialize)]
struct Config {
    mkdir: Option<Vec<String>>,
    touch: Option<Vec<String>>,
    exec: Option<Vec<String>>,
    gitignore: Option<Vec<String>>,
    include: Option<Vec<String>>,
    order: Option<Vec<String>>,
}

fn main() {
    let matches = cli::build_cli().get_matches();
    let lang = matches.value_of("lang").unwrap();

    if let Some(matches) = matches.subcommand_matches("new") {
        println!("doing new {}", matches.value_of("NAME").unwrap());
    }

    let config_path = match get_config_path(&lang.to_string()) {
        Some(p) => p,
        None => {
            println!("Could not find home directory");
            exit(1);
        }
    };

    let config: Config = match parse_config(config_path) {
        Ok(c) => c,
        Err(err) => {
            println!("Error while parsing config! {:?}", err);
            exit(1);
        }
    };

    if let Some(subcmd) = matches.subcommand_matches("new") {
        let name = subcmd.value_of("NAME").unwrap();
        if file_exists(&name.to_string()) {
            println!("A file or directory with that name already exists");
            exit(1);
        } else {
            match create_dir(name.clone()) {
                Ok(_) => println!("Created directory '{}'", name),
                Err(e) => {
                    println!("Could not create directory '{}'. {:?}", name, e);
                    exit(1);
                }
            }
            if let Err(_) = env::set_current_dir(Path::new(&*name)) {
                println!("Could not change directory!");
                exit(1);
            }
        }
    }

    if !dir_is_empty(&".".to_string()) {
        println!("Directory is not empty!");
        exit(1);
    }

    if let Some(ref includes) = config.include {
        for incl in includes {
            let path = match get_config_path(&incl) {
                Some(p) => p,
                None => {
                    println!("Could not resolve home directory");
                    exit(1);
                }
            };

            let conf: Config = match parse_config(path) {
                Ok(c) => c,
                Err(e) => {
                    println!("Could not read include '{}'. {}", incl, e);
                    exit(1);
                }
            };
            process_config(conf);
        }
    }

    process_config(config);

}

fn mkdir(dirs: &Option<Vec<String>>) {
    if let Some(ref dirs) = *dirs {
        for dir in dirs {
            if !file_exists(&dir) {
                match create_dir(dir.clone()) {
                    Ok(_) => println!("Created directory '{}'", dir),
                    Err(e) => println!("Could not create directory '{}'. {:?}", dir, e),
                }
            } else {
                println!("Directory '{}' already exists", dir);
            }
        }
    }
}

fn gitignore(gi: &Option<Vec<String>>) {
    if let Some(ref gi) = *gi {
        let ign = gitignore::get_gitignore(&gi).unwrap();
        let file = OpenOptions::new()
            .create_new(true)
            .append(true)
            .open(".gitignore");
        if let Ok(mut file) = file {
            match writeln!(file, "{}", ign) {
                Ok(_) => {}
                Err(e) => println!("Could not write .gitignore. {:?}", e),
            }
        } else {
            println!("Could not write .gitignore");
        }
    }
}

fn touch(files: &Option<Vec<String>>) {
    if let Some(ref fnames) = *files {
        for file in fnames {
            if !create_file(&file) {
                println!("Could not create file '{}'", file);
            }
        }
    }
}

fn exec_list(cmd_list: &Option<Vec<String>>) {
    if let Some(ref cmds) = *cmd_list {
        for cmd in cmds {
            println!("Executing '{}'", cmd);
            match exec(&cmd) {
                Ok((out, err)) => {
                    println!("stdout: {}", out);
                    println!("stderr: {}", err);
                }
                Err(e) => println!("Failed to execute: {:?}", e),
            }
        }
    }
}

fn process_config(config: Config) {
    let order: Vec<String> = match config.order {
        Some(order) => order,
        None => {
            vec!["mkdir".to_string(),
                 "gitignore".to_string(),
                 "touch".to_string(),
                 "exec".to_string()]
        }
    };

    for ord in order {
        match &*ord {
            "mkdir" => mkdir(&config.mkdir),
            "gitignore" => gitignore(&config.gitignore),
            "touch" => touch(&config.touch),
            "exec" => exec_list(&config.exec),
            x => println!("Unknown operation \"{}\"", x),
        }
    }
}

/// Returns the config path for a `lang` parameter.
///
/// This method concatenates $HOME with "/.skeleton/{lang}.toml"
///
/// # Examples
///
/// ```
/// let path = get_config_path(&"rust".to_string())
/// ```
fn get_config_path(lang: &String) -> Option<String> {
    let home = match env::home_dir() {
        Some(p) => p,
        None => return None,
    };
    let config_path_cow = home.to_string_lossy();
    let mut config_path = config_path_cow.into_owned();
    // let mut config_path = env!("HOME").to_string();

    config_path.push_str("/.skeleton/");
    config_path.push_str(lang);
    config_path.push_str(".toml");
    Some(config_path)
}

/// Checks if a directory is empty
///
/// # Examples
///
/// ```
/// let dir_is_empty(&".".to_string());
/// ```
fn dir_is_empty(dir: &String) -> bool {
    let paths = match read_dir(dir) {
        Ok(paths) => paths,
        Err(_) => return false,
    };

    for _ in paths {
        return false;
    }
    true
}

/// Checks if a file exists
fn file_exists(name: &String) -> bool {
    Path::new(&name).exists()
}

/// Executes a command using `sh` or `cmd.exe` depending on the used operating system.
///
/// Returns either a `Error` or a tuple `(stdout, stderr)`
fn exec(cmd: &String) -> Result<(String, String)> {
    #[cfg(unix)]
    let shell = "sh";
    #[cfg(unix)]
    let arg1 = "-c";
    #[cfg(windows)]
    let shell = "cmd.exe";
    #[cfg(windows)]
    let arg1 = "/C";

    let out = Command::new(shell).arg(arg1).arg(cmd).output()?;

    Ok((String::from_utf8(out.stdout).unwrap_or("Could not parse stdout".to_string()),
        String::from_utf8(out.stderr).unwrap_or("Could not parse stderr".to_string())))

}

/// Creates a file if it doesn't exist.
fn create_file(file_name: &String) -> bool {
    !file_exists(&file_name) &&
    OpenOptions::new()
        .append(true)
        .create(true)
        .open(file_name)
        .is_ok()
}

/// Parses a configuration file and returns the `Config` struct.
fn parse_config(file_name: String) -> Result<Config> {
    let file = File::open(file_name)?;
    let mut reader = BufReader::new(file);
    let mut contents = String::new();

    reader.read_to_string(&mut contents)?;

    toml::from_str(&contents).map_err(|err| Error::new(ErrorKind::InvalidInput, err))
}

#[test]
fn test_file_exists() {
    assert!(file_exists(&"test/foo.toml".to_string()));
    assert!(!file_exists(&"test/none".to_string()));
}

#[test]
fn test_parse_config() {
    let conf = parse_config("test/foo.toml".to_string()).unwrap();
    let gi = conf.gitignore.unwrap();
    assert_eq!(gi, vec!["rust".to_string(), "vim".to_string()]);

    let mkd = conf.mkdir.unwrap();
    assert_eq!(mkd, vec!["b".to_string()]);

    let touch = conf.touch.unwrap();
    assert_eq!(touch, vec!["a".to_string()]);

    let exec = conf.exec.unwrap();
    assert_eq!(exec, vec!["touch asdf".to_string()]);
}

#[test]
fn test_exec() {
    let (stdout, stderr) = exec(&"echo test".to_string()).unwrap();
    #[cfg(unix)]
    assert_eq!(stdout, "test\n".to_string());
    #[cfg(windows)]
    assert_eq!(stdout, "test \r\n".to_string());
    assert_eq!(stderr, "".to_string());
    let (stdout, stderr) = exec(&"echo test 1>&2".to_string()).unwrap();
    assert_eq!(stdout, "".to_string());
    #[cfg(unix)]
    assert_eq!(stderr, "test\n".to_string());
    #[cfg(windows)]
    assert_eq!(stderr, "test \r\n".to_string());
}

#[test]
fn test_dir_is_empty() {
    let is_empty = dir_is_empty(&"./test".to_string());
    assert!(!is_empty);
    let non_existent = dir_is_empty(&"./non_existent_dir".to_string());
    assert!(!non_existent);
}

#[test]
fn test_get_config_path() {
    let expected = get_config_path(&"foo".to_string()).unwrap();
    let mut actual = env::home_dir().unwrap().to_str().unwrap().to_string();
    actual.push_str("/.skeleton/foo.toml");
    assert_eq!(actual, expected);
}
<commit_msg>Another fix for Windows builds<commit_after>#[macro_use]
extern crate serde_derive;
extern crate toml;
extern crate clap;
extern crate hyper;
extern crate hyper_native_tls;

mod gitignore;
mod cli;

use std::fs::{File, OpenOptions, create_dir, read_dir};
use std::io::{BufReader, Result, Error, ErrorKind};
use std::io::prelude::*;
use std::path::Path;
use std::process::{exit, Command};
use std::env;

#[derive(Deserialize)]
struct Config {
    mkdir: Option<Vec<String>>,
    touch: Option<Vec<String>>,
    exec: Option<Vec<String>>,
    gitignore: Option<Vec<String>>,
    include: Option<Vec<String>>,
    order: Option<Vec<String>>,
}

fn main() {
    let matches = cli::build_cli().get_matches();
    let lang = matches.value_of("lang").unwrap();

    if let Some(matches) = matches.subcommand_matches("new") {
        println!("doing new {}", matches.value_of("NAME").unwrap());
    }

    let config_path = match get_config_path(&lang.to_string()) {
        Some(p) => p,
        None => {
            println!("Could not find home directory");
            exit(1);
        }
    };

    let config: Config = match parse_config(config_path) {
        Ok(c) => c,
        Err(err) => {
            println!("Error while parsing config! {:?}", err);
            exit(1);
        }
    };

    if let Some(subcmd) = matches.subcommand_matches("new") {
        let name = subcmd.value_of("NAME").unwrap();
        if file_exists(&name.to_string()) {
            println!("A file or directory with that name already exists");
            exit(1);
        } else {
            match create_dir(name.clone()) {
                Ok(_) => println!("Created directory '{}'", name),
                Err(e) => {
                    println!("Could not create directory '{}'. {:?}", name, e);
                    exit(1);
                }
            }
            if let Err(_) = env::set_current_dir(Path::new(&*name)) {
                println!("Could not change directory!");
                exit(1);
            }
        }
    }

    if !dir_is_empty(&".".to_string()) {
        println!("Directory is not empty!");
        exit(1);
    }

    if let Some(ref includes) = config.include {
        for incl in includes {
            let path = match get_config_path(&incl) {
                Some(p) => p,
                None => {
                    println!("Could not resolve home directory");
                    exit(1);
                }
            };

            let conf: Config = match parse_config(path) {
                Ok(c) => c,
                Err(e) => {
                    println!("Could not read include '{}'. {}", incl, e);
                    exit(1);
                }
            };
            process_config(conf);
        }
    }

    process_config(config);

}

fn mkdir(dirs: &Option<Vec<String>>) {
    if let Some(ref dirs) = *dirs {
        for dir in dirs {
            if !file_exists(&dir) {
                match create_dir(dir.clone()) {
                    Ok(_) => println!("Created directory '{}'", dir),
                    Err(e) => println!("Could not create directory '{}'. {:?}", dir, e),
                }
            } else {
                println!("Directory '{}' already exists", dir);
            }
        }
    }
}

fn gitignore(gi: &Option<Vec<String>>) {
    if let Some(ref gi) = *gi {
        let ign = gitignore::get_gitignore(&gi).unwrap();
        let file = OpenOptions::new()
            .create_new(true)
            .append(true)
            .open(".gitignore");
        if let Ok(mut file) = file {
            match writeln!(file, "{}", ign) {
                Ok(_) => {}
                Err(e) => println!("Could not write .gitignore. {:?}", e),
            }
        } else {
            println!("Could not write .gitignore");
        }
    }
}

fn touch(files: &Option<Vec<String>>) {
    if let Some(ref fnames) = *files {
        for file in fnames {
            if !create_file(&file) {
                println!("Could not create file '{}'", file);
            }
        }
    }
}

fn exec_list(cmd_list: &Option<Vec<String>>) {
    if let Some(ref cmds) = *cmd_list {
        for cmd in cmds {
            println!("Executing '{}'", cmd);
            match exec(&cmd) {
                Ok((out, err)) => {
                    println!("stdout: {}", out);
                    println!("stderr: {}", err);
                }
                Err(e) => println!("Failed to execute: {:?}", e),
            }
        }
    }
}

fn process_config(config: Config) {
    let order: Vec<String> = match config.order {
        Some(order) => order,
        None => {
            vec!["mkdir".to_string(),
                 "gitignore".to_string(),
                 "touch".to_string(),
                 "exec".to_string()]
        }
    };

    for ord in order {
        match &*ord {
            "mkdir" => mkdir(&config.mkdir),
            "gitignore" => gitignore(&config.gitignore),
            "touch" => touch(&config.touch),
            "exec" => exec_list(&config.exec),
            x => println!("Unknown operation \"{}\"", x),
        }
    }
}

/// Returns the config path for a `lang` parameter.
///
/// This method concatenates $HOME with "/.skeleton/{lang}.toml"
///
/// # Examples
///
/// ```
/// let path = get_config_path(&"rust".to_string())
/// ```
fn get_config_path(lang: &String) -> Option<String> {
    let home = match env::home_dir() {
        Some(p) => p,
        None => return None,
    };
    let config_path_cow = home.to_string_lossy();
    let mut config_path = config_path_cow.into_owned();
    // let mut config_path = env!("HOME").to_string();

    config_path.push_str("/.skeleton/");
    config_path.push_str(lang);
    config_path.push_str(".toml");
    Some(config_path)
}

/// Checks if a directory is empty
///
/// # Examples
///
/// ```
/// let dir_is_empty(&".".to_string());
/// ```
fn dir_is_empty(dir: &String) -> bool {
    let paths = match read_dir(dir) {
        Ok(paths) => paths,
        Err(_) => return false,
    };

    for _ in paths {
        return false;
    }
    true
}

/// Checks if a file exists
fn file_exists(name: &String) -> bool {
    Path::new(&name).exists()
}

/// Executes a command using `sh` or `cmd.exe` depending on the used operating system.
///
/// Returns either a `Error` or a tuple `(stdout, stderr)`
fn exec(cmd: &String) -> Result<(String, String)> {
    #[cfg(unix)]
    let shell = "sh";
    #[cfg(unix)]
    let arg1 = "-c";
    #[cfg(windows)]
    let shell = "cmd.exe";
    #[cfg(windows)]
    let arg1 = "/C";

    let out = Command::new(shell).arg(arg1).arg(cmd).output()?;

    Ok((String::from_utf8(out.stdout).unwrap_or("Could not parse stdout".to_string()),
        String::from_utf8(out.stderr).unwrap_or("Could not parse stderr".to_string())))

}

/// Creates a file if it doesn't exist.
fn create_file(file_name: &String) -> bool {
    !file_exists(&file_name) &&
    OpenOptions::new()
        .append(true)
        .create(true)
        .open(file_name)
        .is_ok()
}

/// Parses a configuration file and returns the `Config` struct.
fn parse_config(file_name: String) -> Result<Config> {
    let file = File::open(file_name)?;
    let mut reader = BufReader::new(file);
    let mut contents = String::new();

    reader.read_to_string(&mut contents)?;

    toml::from_str(&contents).map_err(|err| Error::new(ErrorKind::InvalidInput, err))
}

#[test]
fn test_file_exists() {
    assert!(file_exists(&"test/foo.toml".to_string()));
    assert!(!file_exists(&"test/none".to_string()));
}

#[test]
fn test_parse_config() {
    let conf = parse_config("test/foo.toml".to_string()).unwrap();
    let gi = conf.gitignore.unwrap();
    assert_eq!(gi, vec!["rust".to_string(), "vim".to_string()]);

    let mkd = conf.mkdir.unwrap();
    assert_eq!(mkd, vec!["b".to_string()]);

    let touch = conf.touch.unwrap();
    assert_eq!(touch, vec!["a".to_string()]);

    let exec = conf.exec.unwrap();
    assert_eq!(exec, vec!["touch asdf".to_string()]);
}

#[test]
fn test_exec() {
    let (stdout, stderr) = exec(&"echo test".to_string()).unwrap();
    #[cfg(unix)]
    assert_eq!(stdout, "test\n".to_string());
    #[cfg(windows)]
    assert_eq!(stdout, "test\r\n".to_string());
    assert_eq!(stderr, "".to_string());
    let (stdout, stderr) = exec(&"echo test 1>&2".to_string()).unwrap();
    assert_eq!(stdout, "".to_string());
    #[cfg(unix)]
    assert_eq!(stderr, "test\n".to_string());
    #[cfg(windows)]
    assert_eq!(stderr, "test \r\n".to_string());
}

#[test]
fn test_dir_is_empty() {
    let is_empty = dir_is_empty(&"./test".to_string());
    assert!(!is_empty);
    let non_existent = dir_is_empty(&"./non_existent_dir".to_string());
    assert!(!non_existent);
}

#[test]
fn test_get_config_path() {
    let expected = get_config_path(&"foo".to_string()).unwrap();
    let mut actual = env::home_dir().unwrap().to_str().unwrap().to_string();
    actual.push_str("/.skeleton/foo.toml");
    assert_eq!(actual, expected);
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate walkdir;
extern crate twox_hash;

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

use clap::{App, Arg};
use walkdir::WalkDir;
use twox_hash::XxHash;
use std::hash::Hasher;

fn main() {
    let matches = App::new("dupr")
        .version("0.1.0")
        .author("Mike Sampson")
        .about("Duplicate file finder")
        .arg(
            Arg::with_name("DIR")
                .help("Directory to process")
                .required(true),
        )
        .get_matches();

    let mut files = HashMap::new();

    for entry in WalkDir::new(matches.value_of("DIR").unwrap()) {
        let entry = entry.unwrap();

        if !entry.file_type().is_file() {
            continue;
        }

        let metadata = entry.metadata().unwrap();

        let path = entry.path().to_path_buf();

        files.entry(metadata.len()).or_insert(Vec::new()).push(path);
    }

    for (f_len, f_paths) in files {
        println!("=== {} - {} ===", f_len, f_paths.len());
        for f_path in f_paths {
            println!("    {} - {:x}", f_path.display(), hash_file(&f_path));
        }
    }
}

fn hash_file<P: AsRef<Path>>(path: P) -> u64 {
    let mut file = File::open(path).unwrap();

    let mut hash = XxHash::with_seed(0);

    let mut buffer = [0; 32 * 1024];

    while let Ok(n) = file.read(&mut buffer) {
        if n == 0 {
            break;
        }
        hash.write(&buffer[0 .. n]);
    }

    hash.finish()
}

<commit_msg>cargo fmt fix<commit_after>extern crate clap;
extern crate walkdir;
extern crate twox_hash;

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

use clap::{App, Arg};
use walkdir::WalkDir;
use twox_hash::XxHash;
use std::hash::Hasher;

fn main() {
    let matches = App::new("dupr")
        .version("0.1.0")
        .author("Mike Sampson")
        .about("Duplicate file finder")
        .arg(
            Arg::with_name("DIR")
                .help("Directory to process")
                .required(true),
        )
        .get_matches();

    let mut files = HashMap::new();

    for entry in WalkDir::new(matches.value_of("DIR").unwrap()) {
        let entry = entry.unwrap();

        if !entry.file_type().is_file() {
            continue;
        }

        let metadata = entry.metadata().unwrap();

        let path = entry.path().to_path_buf();

        files.entry(metadata.len()).or_insert(Vec::new()).push(path);
    }

    for (f_len, f_paths) in files {
        println!("=== {} - {} ===", f_len, f_paths.len());
        for f_path in f_paths {
            println!("    {} - {:x}", f_path.display(), hash_file(&f_path));
        }
    }
}

fn hash_file<P: AsRef<Path>>(path: P) -> u64 {
    let mut file = File::open(path).unwrap();

    let mut hash = XxHash::with_seed(0);

    let mut buffer = [0; 32 * 1024];

    while let Ok(n) = file.read(&mut buffer) {
        if n == 0 {
            break;
        }
        hash.write(&buffer[0..n]);
    }

    hash.finish()
}
<|endoftext|>


<commit_before>#![deny(bare_trait_objects, anonymous_parameters, elided_lifetimes_in_paths)]

use cargo;
use env_logger;

#[macro_use]
mod macros;
mod cargo_ops;
use crate::cargo_ops::{ElaborateWorkspace, TempProject};

use cargo::core::maybe_allow_nightly_features;
use cargo::core::shell::Verbosity;
use cargo::core::Workspace;
use cargo::util::important_paths::find_root_manifest_for_wd;
use cargo::util::{CargoResult, CliError, Config};
use docopt::Docopt;

pub const USAGE: &str = "
Displays information about project dependency versions

USAGE:
    cargo outdated [options]

Options:
    -a, --aggressive            Ignores channels for latest updates
    -h, --help                  Prints help information
        --format FORMAT         Output formatting [default: list]
                                [values: list, json]
    -q, --quiet                 Suppresses warnings
    -R, --root-deps-only        Only check root dependencies (Equivalent to --depth=1)
    -V, --version               Prints version information
    -v, --verbose ...           Use verbose output
    -w, --workspace             Checks updates for all workspace members rather than
                                only the root package
        --color COLOR           Coloring: auto, always, never [default: auto]
                                [values: auto, always, never]
    -d, --depth NUM             How deep in the dependency chain to search
                                (Defaults to all dependencies when omitted)
        --exit-code NUM         The exit code to return on new versions found [default: 0]
        --features FEATURES     Space-separated list of features
    -m, --manifest-path FILE    An absolute path to the Cargo.toml file to use
                                (Defaults to Cargo.toml in project root)
    -p, --packages PKGS         Packages to inspect for updates
    -r, --root ROOT             Package to treat as the root package
";

/// Options from CLI arguments
#[derive(serde_derive::Deserialize, Debug)]
pub struct Options {
    flag_format: Option<String>,
    flag_color: Option<String>,
    flag_features: Vec<String>,
    flag_manifest_path: Option<String>,
    flag_quiet: bool,
    flag_verbose: u32,
    flag_exit_code: i32,
    flag_packages: Vec<String>,
    flag_root: Option<String>,
    flag_depth: Option<i32>,
    flag_root_deps_only: bool,
    flag_workspace: bool,
    flag_aggressive: bool,
}

impl Options {
    fn all_features(&self) -> bool { self.flag_features.is_empty() }

    fn no_default_features(&self) -> bool {
        !(self.flag_features.is_empty() || self.flag_features.contains(&"default".to_owned()))
    }

    fn locked(&self) -> bool { false }

    fn frozen(&self) -> bool { false }
}

fn main() {
    env_logger::init();
    let options = {
        let mut options: Options = Docopt::new(USAGE)
            .and_then(|d| {
                d.version(Some(
                    concat!(env!("CARGO_PKG_NAME"), " v", env!("CARGO_PKG_VERSION")).to_owned(),
                ))
                .deserialize()
            })
            .unwrap_or_else(|e| e.exit());
        fn flat_split(arg: &[String]) -> Vec<String> {
            arg.iter()
                .flat_map(|s| s.split_whitespace())
                .flat_map(|s| s.split(','))
                .filter(|s| !s.is_empty())
                .map(ToString::to_string)
                .collect()
        }
        options.flag_features = flat_split(&options.flag_features);
        options.flag_packages = flat_split(&options.flag_packages);
        if options.flag_root_deps_only {
            options.flag_depth = Some(1);
        }
        options
    };

    let mut config = match Config::default() {
        Ok(cfg) => cfg,
        Err(e) => {
            let mut shell = cargo::core::Shell::new();
            cargo::exit_with_error(e.into(), &mut shell)
        }
    };
    let exit_code = options.flag_exit_code;
    let result = execute(options, &mut config);
    match result {
        Err(e) => {
            config.shell().set_verbosity(Verbosity::Normal);
            let cli_error = CliError::new(e, 1);
            cargo::exit_with_error(cli_error, &mut *config.shell())
        }
        Ok(i) => {
            if i > 0 {
                std::process::exit(exit_code);
            } else {
                std::process::exit(0);
            }
        }
    }
}

pub fn execute(options: Options, config: &mut Config) -> CargoResult<i32> {
    config.configure(
        options.flag_verbose,
        None,
        &options.flag_color,
        options.frozen(),
        options.locked(),
        false,
        &None,
        &[],
    )?;
    debug!(config, format!("options: {:?}", options));

    // Needed to allow nightly features
    maybe_allow_nightly_features();

    verbose!(config, "Parsing...", "current workspace");
    // the Cargo.toml that we are actually working on
    let curr_manifest = if let Some(ref manifest_path) = options.flag_manifest_path {
        manifest_path.into()
    } else {
        find_root_manifest_for_wd(config.cwd())?
    };
    let curr_workspace = Workspace::new(&curr_manifest, config)?;
    verbose!(config, "Resolving...", "current workspace");
    if options.flag_verbose == 0 {
        config.shell().set_verbosity(Verbosity::Quiet);
    }
    let ela_curr = ElaborateWorkspace::from_workspace(&curr_workspace, &options)?;
    if options.flag_verbose > 0 {
        config.shell().set_verbosity(Verbosity::Verbose);
    } else {
        config.shell().set_verbosity(Verbosity::Normal);
    }

    verbose!(config, "Parsing...", "compat workspace");
    let compat_proj =
        TempProject::from_workspace(&ela_curr, &curr_manifest.to_string_lossy(), &options)?;
    compat_proj.write_manifest_semver(
        curr_workspace.root(),
        compat_proj.temp_dir.path(),
        &ela_curr,
    )?;
    verbose!(config, "Updating...", "compat workspace");
    compat_proj.cargo_update()?;
    verbose!(config, "Resolving...", "compat workspace");
    let compat_workspace = compat_proj.workspace.borrow();
    let ela_compat =
        ElaborateWorkspace::from_workspace(compat_workspace.as_ref().unwrap(), &options)?;

    verbose!(config, "Parsing...", "latest workspace");
    let latest_proj =
        TempProject::from_workspace(&ela_curr, &curr_manifest.to_string_lossy(), &options)?;
    latest_proj.write_manifest_latest(
        curr_workspace.root(),
        compat_proj.temp_dir.path(),
        &ela_curr,
    )?;
    verbose!(config, "Updating...", "latest workspace");
    latest_proj.cargo_update()?;
    verbose!(config, "Resolving...", "latest workspace");
    let latest_workspace = latest_proj.workspace.borrow();
    let ela_latest =
        ElaborateWorkspace::from_workspace(latest_workspace.as_ref().unwrap(), &options)?;

    if ela_curr.workspace_mode {
        let mut sum = 0;
        if options.flag_format == Some("list".to_string()) {
            verbose!(config, "Printing...", "Package status in list format");
        } else if options.flag_format == Some("json".to_string()) {
            verbose!(config, "Printing...", "Package status in json format");
        }

        for member in ela_curr.workspace.members() {
            ela_curr.resolve_status(
                &ela_compat,
                &ela_latest,
                &options,
                config,
                member.package_id(),
            )?;
            if options.flag_format == Some("list".to_string()) {
                sum += ela_curr.print_list(&options, member.package_id(), sum > 0)?;
            } else if options.flag_format == Some("json".to_string()) {
                sum += ela_curr.print_json(&options, member.package_id())?;
            }
        }
        if sum == 0 {
            println!("All dependencies are up to date, yay!");
        }
        Ok(sum)
    } else {
        verbose!(config, "Resolving...", "package status");
        let root = ela_curr.determine_root(&options)?;
        ela_curr.resolve_status(&ela_compat, &ela_latest, &options, config, root)?;
        verbose!(config, "Printing...", "list format");
        let mut count = 0;

        if options.flag_format == Some("list".to_string()) {
            count = ela_curr.print_list(&options, root, false)?;
        } else if options.flag_format == Some("json".to_string()) {
            ela_curr.print_json(&options, root)?;
        } else {
            println!("Error, did not specify list or json output formatting");
            std::process::exit(2);
        }

        Ok(count)
    }
}
<commit_msg>Allow relative manifest path<commit_after>#![deny(bare_trait_objects, anonymous_parameters, elided_lifetimes_in_paths)]

use cargo;
use env_logger;

#[macro_use]
mod macros;
mod cargo_ops;
use crate::cargo_ops::{ElaborateWorkspace, TempProject};

use cargo::core::maybe_allow_nightly_features;
use cargo::core::shell::Verbosity;
use cargo::core::Workspace;
use cargo::util::important_paths::find_root_manifest_for_wd;
use cargo::util::{CargoResult, CliError, Config};
use docopt::Docopt;

pub const USAGE: &str = "
Displays information about project dependency versions

USAGE:
    cargo outdated [options]

Options:
    -a, --aggressive            Ignores channels for latest updates
    -h, --help                  Prints help information
        --format FORMAT         Output formatting [default: list]
                                [values: list, json]
    -q, --quiet                 Suppresses warnings
    -R, --root-deps-only        Only check root dependencies (Equivalent to --depth=1)
    -V, --version               Prints version information
    -v, --verbose ...           Use verbose output
    -w, --workspace             Checks updates for all workspace members rather than
                                only the root package
        --color COLOR           Coloring: auto, always, never [default: auto]
                                [values: auto, always, never]
    -d, --depth NUM             How deep in the dependency chain to search
                                (Defaults to all dependencies when omitted)
        --exit-code NUM         The exit code to return on new versions found [default: 0]
        --features FEATURES     Space-separated list of features
    -m, --manifest-path FILE    Path to the Cargo.toml file to use
                                (Defaults to Cargo.toml in project root)
    -p, --packages PKGS         Packages to inspect for updates
    -r, --root ROOT             Package to treat as the root package
";

/// Options from CLI arguments
#[derive(serde_derive::Deserialize, Debug)]
pub struct Options {
    flag_format: Option<String>,
    flag_color: Option<String>,
    flag_features: Vec<String>,
    flag_manifest_path: Option<String>,
    flag_quiet: bool,
    flag_verbose: u32,
    flag_exit_code: i32,
    flag_packages: Vec<String>,
    flag_root: Option<String>,
    flag_depth: Option<i32>,
    flag_root_deps_only: bool,
    flag_workspace: bool,
    flag_aggressive: bool,
}

impl Options {
    fn all_features(&self) -> bool { self.flag_features.is_empty() }

    fn no_default_features(&self) -> bool {
        !(self.flag_features.is_empty() || self.flag_features.contains(&"default".to_owned()))
    }

    fn locked(&self) -> bool { false }

    fn frozen(&self) -> bool { false }
}

fn main() {
    env_logger::init();
    let options = {
        let mut options: Options = Docopt::new(USAGE)
            .and_then(|d| {
                d.version(Some(
                    concat!(env!("CARGO_PKG_NAME"), " v", env!("CARGO_PKG_VERSION")).to_owned(),
                ))
                .deserialize()
            })
            .unwrap_or_else(|e| e.exit());
        fn flat_split(arg: &[String]) -> Vec<String> {
            arg.iter()
                .flat_map(|s| s.split_whitespace())
                .flat_map(|s| s.split(','))
                .filter(|s| !s.is_empty())
                .map(ToString::to_string)
                .collect()
        }
        options.flag_features = flat_split(&options.flag_features);
        options.flag_packages = flat_split(&options.flag_packages);
        if options.flag_root_deps_only {
            options.flag_depth = Some(1);
        }
        options
    };

    let mut config = match Config::default() {
        Ok(cfg) => cfg,
        Err(e) => {
            let mut shell = cargo::core::Shell::new();
            cargo::exit_with_error(e.into(), &mut shell)
        }
    };
    let exit_code = options.flag_exit_code;
    let result = execute(options, &mut config);
    match result {
        Err(e) => {
            config.shell().set_verbosity(Verbosity::Normal);
            let cli_error = CliError::new(e, 1);
            cargo::exit_with_error(cli_error, &mut *config.shell())
        }
        Ok(i) => {
            if i > 0 {
                std::process::exit(exit_code);
            } else {
                std::process::exit(0);
            }
        }
    }
}

pub fn execute(options: Options, config: &mut Config) -> CargoResult<i32> {
    config.configure(
        options.flag_verbose,
        None,
        &options.flag_color,
        options.frozen(),
        options.locked(),
        false,
        &None,
        &[],
    )?;
    debug!(config, format!("options: {:?}", options));

    // Needed to allow nightly features
    maybe_allow_nightly_features();

    verbose!(config, "Parsing...", "current workspace");
    // the Cargo.toml that we are actually working on
    let mut manifest_abspath: std::path::PathBuf;
    let curr_manifest = if let Some(ref manifest_path) = options.flag_manifest_path {
        manifest_abspath = manifest_path.into();
        if manifest_abspath.is_relative() {
            verbose!(config, "Resolving...", "absolute path of manifest");
            manifest_abspath = std::env::current_dir()?.join(manifest_path);
        }
        manifest_abspath
    } else {
        find_root_manifest_for_wd(config.cwd())?
    };
    let curr_workspace = Workspace::new(&curr_manifest, config)?;
    verbose!(config, "Resolving...", "current workspace");
    if options.flag_verbose == 0 {
        config.shell().set_verbosity(Verbosity::Quiet);
    }
    let ela_curr = ElaborateWorkspace::from_workspace(&curr_workspace, &options)?;
    if options.flag_verbose > 0 {
        config.shell().set_verbosity(Verbosity::Verbose);
    } else {
        config.shell().set_verbosity(Verbosity::Normal);
    }

    verbose!(config, "Parsing...", "compat workspace");
    let compat_proj =
        TempProject::from_workspace(&ela_curr, &curr_manifest.to_string_lossy(), &options)?;
    compat_proj.write_manifest_semver(
        curr_workspace.root(),
        compat_proj.temp_dir.path(),
        &ela_curr,
    )?;
    verbose!(config, "Updating...", "compat workspace");
    compat_proj.cargo_update()?;
    verbose!(config, "Resolving...", "compat workspace");
    let compat_workspace = compat_proj.workspace.borrow();
    let ela_compat =
        ElaborateWorkspace::from_workspace(compat_workspace.as_ref().unwrap(), &options)?;

    verbose!(config, "Parsing...", "latest workspace");
    let latest_proj =
        TempProject::from_workspace(&ela_curr, &curr_manifest.to_string_lossy(), &options)?;
    latest_proj.write_manifest_latest(
        curr_workspace.root(),
        compat_proj.temp_dir.path(),
        &ela_curr,
    )?;
    verbose!(config, "Updating...", "latest workspace");
    latest_proj.cargo_update()?;
    verbose!(config, "Resolving...", "latest workspace");
    let latest_workspace = latest_proj.workspace.borrow();
    let ela_latest =
        ElaborateWorkspace::from_workspace(latest_workspace.as_ref().unwrap(), &options)?;

    if ela_curr.workspace_mode {
        let mut sum = 0;
        if options.flag_format == Some("list".to_string()) {
            verbose!(config, "Printing...", "Package status in list format");
        } else if options.flag_format == Some("json".to_string()) {
            verbose!(config, "Printing...", "Package status in json format");
        }

        for member in ela_curr.workspace.members() {
            ela_curr.resolve_status(
                &ela_compat,
                &ela_latest,
                &options,
                config,
                member.package_id(),
            )?;
            if options.flag_format == Some("list".to_string()) {
                sum += ela_curr.print_list(&options, member.package_id(), sum > 0)?;
            } else if options.flag_format == Some("json".to_string()) {
                sum += ela_curr.print_json(&options, member.package_id())?;
            }
        }
        if sum == 0 {
            println!("All dependencies are up to date, yay!");
        }
        Ok(sum)
    } else {
        verbose!(config, "Resolving...", "package status");
        let root = ela_curr.determine_root(&options)?;
        ela_curr.resolve_status(&ela_compat, &ela_latest, &options, config, root)?;
        verbose!(config, "Printing...", "list format");
        let mut count = 0;

        if options.flag_format == Some("list".to_string()) {
            count = ela_curr.print_list(&options, root, false)?;
        } else if options.flag_format == Some("json".to_string()) {
            ela_curr.print_json(&options, root)?;
        } else {
            println!("Error, did not specify list or json output formatting");
            std::process::exit(2);
        }

        Ok(count)
    }
}
<|endoftext|>


<commit_before>extern crate mmap;

use std::ptr;
use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use mmap::{MemoryMap, MapOption};
use std::os::unix::prelude::AsRawFd;

const BCM2708_PERI_BASE: u32 = 0x20000000;
const GPIO_BASE: u8 = (BCM2708_PERI_BASE + 0x200000) as u8;
const O_SYNC: u32 = 1052672;
const MAP_SHARED: i32 = 0x0001;
const BLOCK_SIZE: usize = (4*1024);

#[allow(dead_code)]
struct Bcm2835Peripheral {
    addr_p: *const u8,
    mem_fd: std::fs::File,
    map: mmap::MemoryMap,
    addr: *mut u8
}

impl Drop for Bcm2835Peripheral {
    fn drop(&mut self) {
        println!("Unmapped Peripheral {:?}", self.map.data())
    }
}

fn main() {
    let mut gpio = Bcm2835Peripheral { addr_p: &GPIO_BASE, mem_fd: OpenOptions::new().create(true).open("temp.txt").unwrap(), map: MemoryMap::new(1024, &[]).unwrap(), addr: ptr::null_mut()};
    map_peripheral(&mut gpio);
    unmap_peripheral(gpio);
}

fn map_peripheral(ref mut foo: &mut Bcm2835Peripheral) {
    foo.mem_fd = OpenOptions::new()
                    .read(true)
                    .write(true)
                    .mode(O_SYNC)
                    .open("/dev/mem")
                    .expect("unable to open /dev/mem, Are you root?");

    let map_opts = &[
        MapOption::MapNonStandardFlags(MAP_SHARED),
        MapOption::MapReadable,
        MapOption::MapWritable,
       // MapOption::MapAddr(foo.addr_p),
        MapOption::MapFd(foo.mem_fd.as_raw_fd())
    ];

   let mmap = match MemoryMap::new(BLOCK_SIZE, map_opts) {
     Ok(mmap) => mmap,
     Err(e) => panic!("ERR: {}", e)
    };
    foo.map = mmap;
    foo.addr = foo.map.data();
}

fn unmap_peripheral(foo: Bcm2835Peripheral) {
    drop(foo);
}

fn in_gpio(foo: &Bcm2835Peripheral, y: isize) {
  unsafe {
      let k = &foo.addr.offset(y/10);
      **k &= !(7<<(((y)%10)*3));
  }
}

fn out_gpio(foo: &Bcm2835Peripheral, y:isize) {
  unsafe {
      let k = &foo.addr.offset(y/10);
      **k |= (7<<(((y)%10)*3));
  }
}

fn set_gpio_alt(foo: &Bcm2835Peripheral, y:isize, a:u8) {
    unsafe {
        let k = &foo.addr.offset(y/10);
        **k |= match a {
            a if a<=3 => a+4,
            4         => 3,
            _         => 2,
        } << ((y % 10) * 3);
    }
}

<commit_msg>Update main.rs<commit_after>extern crate mmap;

use std::ptr;
use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use mmap::{MemoryMap, MapOption};
use std::os::unix::prelude::AsRawFd;

const BCM2708_PERI_BASE: u32 = 0x20000000;
const GPIO_BASE: u8 = (BCM2708_PERI_BASE + 0x200000) as u8;
const O_SYNC: u32 = 1052672;
const MAP_SHARED: i32 = 0x0001;
const BLOCK_SIZE: usize = (4*1024);

#[allow(dead_code)]
struct Bcm2835Peripheral {
    addr_p: *const u8,
    mem_fd: std::fs::File,
    map: mmap::MemoryMap,
    addr: *mut u8
}

impl Drop for Bcm2835Peripheral {
    fn drop(&mut self) {
        println!("Unmapped Peripheral {:?}", self.map.data())
    }
}

fn main() {
    let mut gpio = Bcm2835Peripheral { addr_p: &GPIO_BASE, mem_fd: OpenOptions::new().create(true).open("temp.txt").unwrap(), map: MemoryMap::new(1024, &[]).unwrap(), addr: ptr::null_mut()};
    map_peripheral(&mut gpio);
    unmap_peripheral(gpio);
}

fn map_peripheral(ref mut foo: &mut Bcm2835Peripheral) {
    foo.mem_fd = OpenOptions::new()
                    .read(true)
                    .write(true)
                    .mode(O_SYNC)
                    .open("/dev/mem")
                    .expect("unable to open /dev/mem, Are you root?");

    let map_opts = &[
        MapOption::MapNonStandardFlags(MAP_SHARED),
        MapOption::MapReadable,
        MapOption::MapWritable,
       // MapOption::MapAddr(foo.addr_p),
        MapOption::MapFd(foo.mem_fd.as_raw_fd())
    ];

   let mmap = match MemoryMap::new(BLOCK_SIZE, map_opts) {
     Ok(mmap) => mmap,
     Err(e) => panic!("ERR: {}", e)
    };
    foo.map = mmap;
    foo.addr = foo.map.data();
}

fn unmap_peripheral(foo: Bcm2835Peripheral) {
    drop(foo);
}

fn in_gpio(foo: &Bcm2835Peripheral, y: isize) {
  unsafe {
      let k = &foo.addr.offset(y/10);
      **k &= !(7<<(((y)%10)*3));
  }
}

fn out_gpio(foo: &Bcm2835Peripheral, y:isize) {
  unsafe {
      let k = &foo.addr.offset(y/10);
      **k |= (7<<(((y)%10)*3));
  }
}

fn set_gpio_alt(foo: &Bcm2835Peripheral, y:isize, a:u8) {
    unsafe {
        let k = &foo.addr.offset(y/10);
        **k |= match a {
            a if a<=3 => a+4,
            4         => 3,
            _         => 2,
        } << ((y % 10) * 3);
    }
}

fn set_gpio(foo: &Bcm2835Peripheral, val: *mut u8) {
    foo.addr.offset(7) = val;                            //Invalid left-hand side assignment
}
<|endoftext|>


<commit_before>use syntax::ptr::P;
use syntax::ast;
use syntax::ast::*;
use syntax::visit::{FnKind};
use rustc::lint::{Context, LintPass, LintArray, Lint, Level};
use rustc::middle::ty::{mod, expr_ty, ty_str, ty_ptr, ty_rptr};
use syntax::codemap::Span;

use types::span_note_and_lint;

/// Handles uncategorized lints
/// Currently handles linting of if-let-able matches
#[allow(missing_copy_implementations)]
pub struct MiscPass;

declare_lint!(CLIPPY_SINGLE_MATCH, Warn,
              "Warn on usage of matches with a single nontrivial arm");

impl LintPass for MiscPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(CLIPPY_SINGLE_MATCH)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprMatch(ref ex, ref arms, ast::MatchSource::Normal) = expr.node {
            if arms.len() == 2 {
                if arms[0].guard.is_none() && arms[1].pats.len() == 1 {
                    match arms[1].body.node {
                        ExprTup(ref v) if v.len() == 0 && arms[1].guard.is_none() => (),
                        ExprBlock(ref b) if b.stmts.len() == 0 && arms[1].guard.is_none() => (),
                         _ => return
                    }
                    // In some cases, an exhaustive match is preferred to catch situations when
                    // an enum is extended. So we only consider cases where a `_` wildcard is used
                    if arms[1].pats[0].node == PatWild(PatWildSingle) && arms[0].pats.len() == 1 {
                        let map = cx.sess().codemap();
                        span_note_and_lint(cx, CLIPPY_SINGLE_MATCH, expr.span,
                              "You seem to be trying to use match for destructuring a single type. Did you mean to use `if let`?",
                              format!("Try if let {} = {} {{ ... }}",
                                      map.span_to_snippet(arms[0].pats[0].span).unwrap_or("..".to_string()),
                                      map.span_to_snippet(ex.span).unwrap_or("..".to_string())).as_slice()
                        );
                    }
                }
            }
        }
    }
}

declare_lint!(CLIPPY_STR_TO_STRING, Warn, "Warn when a String could use into_string() instead of to_string()");

#[allow(missing_copy_implementations)]
pub struct StrToStringPass;

impl LintPass for StrToStringPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(CLIPPY_STR_TO_STRING)
    }

    fn check_expr(&mut self, cx: &Context, expr: &ast::Expr) {
        match expr.node {
            ast::ExprMethodCall(ref method, _, ref args)
                if method.node.as_str() == "to_string"
                && is_str(cx, &*args[0]) => {
                cx.span_lint(CLIPPY_STR_TO_STRING, expr.span, "str.into_string() is faster");
            },
            _ => ()
        }

        fn is_str(cx: &Context, expr: &ast::Expr) -> bool {
            fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> {
                //println!("{}: -> {}", depth, ty);
                match ty.sty {
                    ty_ptr(ref tm) | ty_rptr(_, ref tm) => walk_ty(tm.ty),
                    _ => ty
                }
            }
            match walk_ty(expr_ty(cx.tcx, expr)).sty {
                ty_str => true,
                _ => false
            }
        }
    }
}

declare_lint!(CLIPPY_TOPLEVEL_REF_ARG, Warn, "Warn about pattern matches with top-level `ref` bindings");

pub struct TopLevelRefPass;

impl LintPass for TopLevelRefPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(CLIPPY_TOPLEVEL_REF_ARG)
    }

    fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) {
        for ref arg in decl.inputs.iter() {
            if let PatIdent(BindByRef(_), _, _) = arg.pat.node {
                cx.span_lint(
                    CLIPPY_TOPLEVEL_REF_ARG,
                    arg.pat.span,
                    "`ref` directly on a function argument is ignored. Have you considered using a reference type instead?"
                );
            }
        }
    }
}
<commit_msg>more rustup<commit_after>use syntax::ptr::P;
use syntax::ast;
use syntax::ast::*;
use syntax::visit::{FnKind};
use rustc::lint::{Context, LintPass, LintArray, Lint, Level};
use rustc::middle::ty::{mod, expr_ty, ty_str, ty_ptr, ty_rptr};
use syntax::codemap::Span;

use types::span_note_and_lint;

/// Handles uncategorized lints
/// Currently handles linting of if-let-able matches
#[allow(missing_copy_implementations)]
pub struct MiscPass;

declare_lint!(CLIPPY_SINGLE_MATCH, Warn,
              "Warn on usage of matches with a single nontrivial arm");

impl LintPass for MiscPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(CLIPPY_SINGLE_MATCH)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprMatch(ref ex, ref arms, ast::MatchSource::Normal) = expr.node {
            if arms.len() == 2 {
                if arms[0].guard.is_none() && arms[1].pats.len() == 1 {
                    match arms[1].body.node {
                        ExprTup(ref v) if v.len() == 0 && arms[1].guard.is_none() => (),
                        ExprBlock(ref b) if b.stmts.len() == 0 && arms[1].guard.is_none() => (),
                         _ => return
                    }
                    // In some cases, an exhaustive match is preferred to catch situations when
                    // an enum is extended. So we only consider cases where a `_` wildcard is used
                    if arms[1].pats[0].node == PatWild(PatWildSingle) && arms[0].pats.len() == 1 {
                        let map = cx.sess().codemap();
                        span_note_and_lint(cx, CLIPPY_SINGLE_MATCH, expr.span,
                              "You seem to be trying to use match for destructuring a single type. Did you mean to use `if let`?",
                              format!("Try if let {} = {} {{ ... }}",
                                      map.span_to_snippet(arms[0].pats[0].span).unwrap_or("..".to_string()),
                                      map.span_to_snippet(ex.span).unwrap_or("..".to_string())).as_slice()
                        );
                    }
                }
            }
        }
    }
}

declare_lint!(CLIPPY_STR_TO_STRING, Warn, "Warn when a String could use into_string() instead of to_string()");

#[allow(missing_copy_implementations)]
pub struct StrToStringPass;

impl LintPass for StrToStringPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(CLIPPY_STR_TO_STRING)
    }

    fn check_expr(&mut self, cx: &Context, expr: &ast::Expr) {
        match expr.node {
            ast::ExprMethodCall(ref method, _, ref args)
                if method.node.as_str() == "to_string"
                && is_str(cx, &*args[0]) => {
                cx.span_lint(CLIPPY_STR_TO_STRING, expr.span, "str.into_string() is faster");
            },
            _ => ()
        }

        fn is_str(cx: &Context, expr: &ast::Expr) -> bool {
            fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> {
                //println!("{}: -> {}", depth, ty);
                match ty.sty {
                    ty_ptr(ref tm) | ty_rptr(_, ref tm) => walk_ty(tm.ty),
                    _ => ty
                }
            }
            match walk_ty(expr_ty(cx.tcx, expr)).sty {
                ty_str => true,
                _ => false
            }
        }
    }
}

declare_lint!(CLIPPY_TOPLEVEL_REF_ARG, Warn, "Warn about pattern matches with top-level `ref` bindings");

#[allow(missing_copy_implementations)]
pub struct TopLevelRefPass;

impl LintPass for TopLevelRefPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(CLIPPY_TOPLEVEL_REF_ARG)
    }

    fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) {
        for ref arg in decl.inputs.iter() {
            if let PatIdent(BindByRef(_), _, _) = arg.pat.node {
                cx.span_lint(
                    CLIPPY_TOPLEVEL_REF_ARG,
                    arg.pat.span,
                    "`ref` directly on a function argument is ignored. Have you considered using a reference type instead?"
                );
            }
        }
    }
}
<|endoftext|>


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

// Communication with the PowerDNS server happens through the http
// server.
// See https://doc.powerdns.com/md/authoritative/backend-remote/ for
// details about the various requests and responses.

use config::Config;
use crypto::digest::Digest;
use crypto::sha1::Sha1;
use errors::*;
use iron::headers::ContentType;
use iron::prelude::*;
use iron::status::{self, Status};
use serde_json;
use std::io::Read;

#[derive(Deserialize)]
struct PdnsRequestParameters {
    // intialize method
    path: Option<String>,
    timeout: Option<String>,

    // lookup method
    qtype: Option<String>,
    qname: Option<String>,
    #[serde(rename="zone-id")]
    zone_id: Option<i32>,
    remote: Option<String>,
    local: Option<String>,
    real_remote: Option<String>,
}

#[derive(Deserialize)]
struct PdnsRequest {
    method: String,
    parameters: PdnsRequestParameters,
}

#[derive(Serialize)]
pub struct PdnsLookupResponse {
    qtype: String,
    qname: String,
    content: String,
    ttl: u32,
    #[serde(skip_serializing_if = "Option::is_none")]
    domain_id: Option<String>,
    #[serde(rename="scopeMask")]
    #[serde(skip_serializing_if = "Option::is_none")]
    scope_mask: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    auth: Option<String>,
}

#[derive(Serialize)]
#[serde(untagged)]
pub enum PdnsResponseParams {
    Lookup(PdnsLookupResponse),
}

#[derive(Serialize)]
pub struct PdnsResponse {
    result: Vec<PdnsResponseParams>,
}

fn pdns_failure(reason: &str) -> IronResult<Response> {
    debug!("pdns_failure: {}", reason);
    let mut response = Response::with("{\"result\":false}");
    response.status = Some(Status::Ok);
    response.headers.set(ContentType::json());
    Ok(response)
}

pub fn pdns_response_as_iron(response: &PdnsResponse) -> IronResult<Response> {
    match serde_json::to_string(response) {
        Ok(serialized) => {
            debug!("Response is: {}", serialized);
            let mut response = Response::with(serialized);
            response.status = Some(Status::Ok);
            response.headers.set(ContentType::json());

            Ok(response)
        }
        Err(err) => {
            error!("{}", err);
            EndpointError::with(status::InternalServerError, 501)
        }
    }
}

pub fn pakegite_query(qname: &str, qtype: &str, config: &Config) -> IronResult<Response> {
    // Pagekite sends dns requests like:
    // dd7251eef7c773a192feb06c0e07ac6020ac.tc730a6b9e2f28f407bb3871e98d3fe4e60c.625558ecb0d283a5b058ba88fb3d9aa11d48.https-4443.fabrice.box.knilxof.org.box.knilxof.org
    // See https://pagekite.net/wiki/Howto/DnsBasedAuthentication
    debug!("PageKite query for {} {}", qtype, qname);

    if qtype != "A" && qtype != "ANY" {
        return pdns_failure(&format!("Unsupported PageKite request type: {}", qtype));
    }

    // Split up the qname.
    let parts: Vec<&str> = qname.split('.').collect();
    let subdomain = format!("{}.box.{}.", parts[4], config.domain);
    let ip = match config
              .domain_db
              .get_record_by_name(&subdomain)
              .recv()
              .unwrap() {
        Ok(record) => {
            let srand = parts[0];
            let token = parts[1];
            let sign = parts[2];
            let proto = parts[3];
            let kite_domain = format!("{}.box.{}", parts[4], config.domain);
            let payload = format!("{}:{}:{}:{}", proto, kite_domain, srand, token);
            let salt = sign[..8].to_owned();

            debug!("{} {} {} {} {}", srand, token, sign, proto, kite_domain);

            // my $calc = sha1_hex($code . $payload . $salt);
            let mut hasher = Sha1::new();
            hasher.input_str(&format!("{}{}{}", record.token, payload, salt));
            let calc = hasher.result_str();

            // $result = (substr($calc, 0, 28) eq substr($sign, 8, 28)) ? '255.255.254.255' : '255.255.255.1';
            let calc_sub = calc[..28].to_owned();
            let sign_sub = sign[8..36].to_owned();

            debug!("Signatures: {} {}", calc_sub, sign_sub);

            if calc_sub == sign_sub {
                "255.255.254.255"
            } else {
                "255.255.255.1"
            }
        }
        Err(_) => {
            // Return 255.255.255.0 to PageKite to indicate failure.
            "255.255.255.0"
        }
    };

    let mut pdns_response = PdnsResponse { result: Vec::new() };

    let ns_record = PdnsLookupResponse {
        qtype: "A".to_owned(),
        qname: qname.to_owned(),
        content: ip.to_owned(),
        ttl: config.dns_ttl,
        domain_id: None,
        scope_mask: None,
        auth: None,
    };
    pdns_response
        .result
        .push(PdnsResponseParams::Lookup(ns_record));

    pdns_response_as_iron(&pdns_response)
}

pub fn pdns_endpoint(req: &mut Request, config: &Config) -> IronResult<Response> {
    // TODO: check where the request is coming from and only allow from pdns.

    info!("GET /pdns");

    // Read the request from the json body.
    let mut s = String::new();
    itry!(req.body.read_to_string(&mut s));

    debug!("Body is: {}", s);

    let input: PdnsRequest = match serde_json::from_str(&s) {
        Ok(value) => value,
        Err(err) => {
            error!("Bad request: {}", err);
            return EndpointError::with(status::BadRequest, 400);
        }
    };

    debug!("pdns request is {}", input.method);

    if input.method == "lookup" {
        let original_qname = input.parameters.qname.unwrap().to_lowercase();
        let mut qname = original_qname.clone();
        let qtype = input.parameters.qtype.unwrap();
        debug!("lookup for qtype={} qname={}", qtype, original_qname);

        // Example payload:
        //
        // {"method": "lookup",
        //  "parameters": {"local": "0.0.0.0",
        //                 "qname": "fabrice.box.knilxof.org.",
        //                 "qtype": "SOA",
        //                 "real-remote": "63.245.221.198/32",
        //                 "remote": "63.245.221.198",
        //                 "zone-id": -1}}

        // If the qname ends up with .box.$domain.box.$domain we consider that it's a PageKite request.
        // When finding such a request, treat it separately.
        if qname.ends_with(&format!(".box.{}.box.{}", config.domain, config.domain)) {
            return pakegite_query(&qname, &qtype, config);
        }

        // If the qname starts with `_acme-challenge.` this is a DNS-01 challenge verification,
        // so remove that part of the domain to retrieve our record.
        // See https://tools.ietf.org/html/draft-ietf-acme-acme-06#section-8.4
        if qname.starts_with("_acme-challenge.") {
            qname = qname[16..].to_owned();
        }

        debug!("final qname={}", qname);

        // Look for a record with for the qname.
        match config
                  .domain_db
                  .get_record_by_name(&qname)
                  .recv()
                  .unwrap() {
            Ok(record) => {
                if record.local_ip.is_none() && qtype == "A" {
                    // No info on this domain, bail out.
                    return pdns_failure("No local_ip");
                }

                // Choose either the local or public ip based on the parameters.remote one.
                let a_record = if record.public_ip.is_some() &&
                                  input.parameters.remote.unwrap() == record.public_ip.unwrap() {
                    // We are inside of the home network, return the local ip for the A record.
                    record.local_ip.unwrap()
                } else {
                    // We are outside of the home network, return the ip of the tunnel
                    // for the A record.
                    config.tunnel_ip.to_owned()
                };

                let mut pdns_response = PdnsResponse { result: Vec::new() };

                if qtype == "SOA" {
                    // Add a "SOA" record.
                    // TODO: don't hardcode the content of this record!
                    let ns_record = PdnsLookupResponse {
                        qtype: "SOA".to_owned(),
                        qname: original_qname.to_owned(),
                        content: "a.dns.gandi.net hostmaster.gandi.net 1476196782 10800 3600 604800 10800"
                            .to_owned(),
                        ttl: config.dns_ttl,
                        domain_id: None,
                        scope_mask: None,
                        auth: None,
                    };
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(ns_record));
                }

                if qtype == "ANY" || qtype == "A" {
                    // Add an "A" record.
                    let ns_record = PdnsLookupResponse {
                        qtype: "A".to_owned(),
                        qname: original_qname.to_owned(),
                        content: a_record,
                        ttl: config.dns_ttl,
                        domain_id: None,
                        scope_mask: None,
                        auth: None,
                    };
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(ns_record));
                }

                if (qtype == "ANY" || qtype == "TXT") && record.dns_challenge.is_some() {
                    // Add a "TXT" record with the dns challenge content.
                    let ns_record = PdnsLookupResponse {
                        qtype: "TXT".to_owned(),
                        qname: original_qname.to_owned(),
                        content: record.dns_challenge.unwrap(),
                        ttl: config.dns_ttl,
                        domain_id: None,
                        scope_mask: None,
                        auth: None,
                    };
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(ns_record));
                }

                return pdns_response_as_iron(&pdns_response);
            }
            Err(_) => {
                // No such domain, return a `false` result to PowerDNS.
                return pdns_failure("No record for this name.");
            }
        }
    }

    pdns_failure(&format!("Unsupported method: {}", input.method))
}
<commit_msg>Fix PageKite detection<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Communication with the PowerDNS server happens through the http
// server.
// See https://doc.powerdns.com/md/authoritative/backend-remote/ for
// details about the various requests and responses.

use config::Config;
use crypto::digest::Digest;
use crypto::sha1::Sha1;
use errors::*;
use iron::headers::ContentType;
use iron::prelude::*;
use iron::status::{self, Status};
use serde_json;
use std::io::Read;

#[derive(Deserialize)]
struct PdnsRequestParameters {
    // intialize method
    path: Option<String>,
    timeout: Option<String>,

    // lookup method
    qtype: Option<String>,
    qname: Option<String>,
    #[serde(rename="zone-id")]
    zone_id: Option<i32>,
    remote: Option<String>,
    local: Option<String>,
    real_remote: Option<String>,
}

#[derive(Deserialize)]
struct PdnsRequest {
    method: String,
    parameters: PdnsRequestParameters,
}

#[derive(Serialize)]
pub struct PdnsLookupResponse {
    qtype: String,
    qname: String,
    content: String,
    ttl: u32,
    #[serde(skip_serializing_if = "Option::is_none")]
    domain_id: Option<String>,
    #[serde(rename="scopeMask")]
    #[serde(skip_serializing_if = "Option::is_none")]
    scope_mask: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    auth: Option<String>,
}

#[derive(Serialize)]
#[serde(untagged)]
pub enum PdnsResponseParams {
    Lookup(PdnsLookupResponse),
}

#[derive(Serialize)]
pub struct PdnsResponse {
    result: Vec<PdnsResponseParams>,
}

fn pdns_failure(reason: &str) -> IronResult<Response> {
    debug!("pdns_failure: {}", reason);
    let mut response = Response::with("{\"result\":false}");
    response.status = Some(Status::Ok);
    response.headers.set(ContentType::json());
    Ok(response)
}

pub fn pdns_response_as_iron(response: &PdnsResponse) -> IronResult<Response> {
    match serde_json::to_string(response) {
        Ok(serialized) => {
            debug!("Response is: {}", serialized);
            let mut response = Response::with(serialized);
            response.status = Some(Status::Ok);
            response.headers.set(ContentType::json());

            Ok(response)
        }
        Err(err) => {
            error!("{}", err);
            EndpointError::with(status::InternalServerError, 501)
        }
    }
}

pub fn pakegite_query(qname: &str, qtype: &str, config: &Config) -> IronResult<Response> {
    // Pagekite sends dns requests like:
    // dd7251eef7c773a192feb06c0e07ac6020ac.tc730a6b9e2f28f407bb3871e98d3fe4e60c.625558ecb0d283a5b058ba88fb3d9aa11d48.https-4443.fabrice.box.knilxof.org.box.knilxof.org
    // See https://pagekite.net/wiki/Howto/DnsBasedAuthentication
    debug!("PageKite query for {} {}", qtype, qname);

    if qtype != "A" && qtype != "ANY" {
        return pdns_failure(&format!("Unsupported PageKite request type: {}", qtype));
    }

    // Split up the qname.
    let parts: Vec<&str> = qname.split('.').collect();
    let subdomain = format!("{}.box.{}.", parts[4], config.domain);
    let ip = match config
              .domain_db
              .get_record_by_name(&subdomain)
              .recv()
              .unwrap() {
        Ok(record) => {
            let srand = parts[0];
            let token = parts[1];
            let sign = parts[2];
            let proto = parts[3];
            let kite_domain = format!("{}.box.{}", parts[4], config.domain);
            let payload = format!("{}:{}:{}:{}", proto, kite_domain, srand, token);
            let salt = sign[..8].to_owned();

            debug!("{} {} {} {} {}", srand, token, sign, proto, kite_domain);

            // my $calc = sha1_hex($code . $payload . $salt);
            let mut hasher = Sha1::new();
            hasher.input_str(&format!("{}{}{}", record.token, payload, salt));
            let calc = hasher.result_str();

            // $result = (substr($calc, 0, 28) eq substr($sign, 8, 28)) ? '255.255.254.255' : '255.255.255.1';
            let calc_sub = calc[..28].to_owned();
            let sign_sub = sign[8..36].to_owned();

            debug!("Signatures: {} {}", calc_sub, sign_sub);

            if calc_sub == sign_sub {
                "255.255.254.255"
            } else {
                "255.255.255.1"
            }
        }
        Err(_) => {
            // Return 255.255.255.0 to PageKite to indicate failure.
            "255.255.255.0"
        }
    };

    let mut pdns_response = PdnsResponse { result: Vec::new() };

    let ns_record = PdnsLookupResponse {
        qtype: "A".to_owned(),
        qname: qname.to_owned(),
        content: ip.to_owned(),
        ttl: config.dns_ttl,
        domain_id: None,
        scope_mask: None,
        auth: None,
    };
    pdns_response
        .result
        .push(PdnsResponseParams::Lookup(ns_record));

    pdns_response_as_iron(&pdns_response)
}

pub fn pdns_endpoint(req: &mut Request, config: &Config) -> IronResult<Response> {
    // TODO: check where the request is coming from and only allow from pdns.

    info!("GET /pdns");

    // Read the request from the json body.
    let mut s = String::new();
    itry!(req.body.read_to_string(&mut s));

    debug!("Body is: {}", s);

    let input: PdnsRequest = match serde_json::from_str(&s) {
        Ok(value) => value,
        Err(err) => {
            error!("Bad request: {}", err);
            return EndpointError::with(status::BadRequest, 400);
        }
    };

    debug!("pdns request is {}", input.method);

    if input.method == "lookup" {
        let original_qname = input.parameters.qname.unwrap().to_lowercase();
        let mut qname = original_qname.clone();
        let qtype = input.parameters.qtype.unwrap();
        debug!("lookup for qtype={} qname={}", qtype, original_qname);

        // Example payload:
        //
        // {"method": "lookup",
        //  "parameters": {"local": "0.0.0.0",
        //                 "qname": "fabrice.box.knilxof.org.",
        //                 "qtype": "SOA",
        //                 "real-remote": "63.245.221.198/32",
        //                 "remote": "63.245.221.198",
        //                 "zone-id": -1}}

        // If the qname ends up with .box.$domain.box.$domain. we consider that it's a PageKite request.
        // When finding such a request, treat it separately.
        if qname.ends_with(&format!(".box.{}.box.{}.", config.domain, config.domain)) {
            return pakegite_query(&qname, &qtype, config);
        }

        // If the qname starts with `_acme-challenge.` this is a DNS-01 challenge verification,
        // so remove that part of the domain to retrieve our record.
        // See https://tools.ietf.org/html/draft-ietf-acme-acme-06#section-8.4
        if qname.starts_with("_acme-challenge.") {
            qname = qname[16..].to_owned();
        }

        debug!("final qname={}", qname);

        // Look for a record with for the qname.
        match config
                  .domain_db
                  .get_record_by_name(&qname)
                  .recv()
                  .unwrap() {
            Ok(record) => {
                if record.local_ip.is_none() && qtype == "A" {
                    // No info on this domain, bail out.
                    return pdns_failure("No local_ip");
                }

                // Choose either the local or public ip based on the parameters.remote one.
                let a_record = if record.public_ip.is_some() &&
                                  input.parameters.remote.unwrap() == record.public_ip.unwrap() {
                    // We are inside of the home network, return the local ip for the A record.
                    record.local_ip.unwrap()
                } else {
                    // We are outside of the home network, return the ip of the tunnel
                    // for the A record.
                    config.tunnel_ip.to_owned()
                };

                let mut pdns_response = PdnsResponse { result: Vec::new() };

                if qtype == "SOA" {
                    // Add a "SOA" record.
                    // TODO: don't hardcode the content of this record!
                    let ns_record = PdnsLookupResponse {
                        qtype: "SOA".to_owned(),
                        qname: original_qname.to_owned(),
                        content: "a.dns.gandi.net hostmaster.gandi.net 1476196782 10800 3600 604800 10800"
                            .to_owned(),
                        ttl: config.dns_ttl,
                        domain_id: None,
                        scope_mask: None,
                        auth: None,
                    };
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(ns_record));
                }

                if qtype == "ANY" || qtype == "A" {
                    // Add an "A" record.
                    let ns_record = PdnsLookupResponse {
                        qtype: "A".to_owned(),
                        qname: original_qname.to_owned(),
                        content: a_record,
                        ttl: config.dns_ttl,
                        domain_id: None,
                        scope_mask: None,
                        auth: None,
                    };
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(ns_record));
                }

                if (qtype == "ANY" || qtype == "TXT") && record.dns_challenge.is_some() {
                    // Add a "TXT" record with the dns challenge content.
                    let ns_record = PdnsLookupResponse {
                        qtype: "TXT".to_owned(),
                        qname: original_qname.to_owned(),
                        content: record.dns_challenge.unwrap(),
                        ttl: config.dns_ttl,
                        domain_id: None,
                        scope_mask: None,
                        auth: None,
                    };
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(ns_record));
                }

                return pdns_response_as_iron(&pdns_response);
            }
            Err(_) => {
                // No such domain, return a `false` result to PowerDNS.
                return pdns_failure("No record for this name.");
            }
        }
    }

    pdns_failure(&format!("Unsupported method: {}", input.method))
}
<|endoftext|>


<commit_before>//!A raytracer.
#![feature(path, io)]
extern crate image;

use std::old_io::File;
use std::num::Float;

use point::Point3;
use vec::Vec3;

mod vec;
mod point;

#[derive(Copy)]
struct Ray3 {
    start: Point3,
    dir: Vec3
}

struct Intersection {
    time: f32,
    normal: Vec3
}

trait Scene {
    fn intersect(&self, ray: Ray3) -> Option<Intersection>;
}

struct Sphere {
    center: Point3,
    radius: f32
}

impl Scene for Sphere {
    fn intersect(&self, ray: Ray3) -> Option<Intersection> {
        let offset = ray.start - self.center;

        let a = ray.dir.mag2();
        let b = 2. * offset.dot(ray.dir);
        let c = offset.mag2() - self.radius*self.radius;

        let descrim = b*b - 4.*a*c;
        if descrim > 0. {
            let t1 = (-b - descrim.sqrt()) / (2. * a);
            let t2 = (-b + descrim.sqrt()) / (2. * a);
            if t1 > 0. {
                let normal = ray.start + ray.dir * t1 - self.center;
                Some(Intersection { time: t1, normal: normal })
            } else if t2 > 0. {
                let normal = ray.start + ray.dir * t2 - self.center;
                Some(Intersection { time: t2, normal: normal })
            } else {
                None
            }
        } else {
            None
        }
    }
}

impl<A: Scene, B: Scene> Scene for (A, B) {
    fn intersect(&self, ray: Ray3) -> Option<Intersection> {
        match self.0.intersect(ray) {
            Some(ai) => {
                match self.1.intersect(ray) {
                    Some(bi) => if ai.time < bi.time {
                        Some(ai)
                    } else {
                        Some(bi)
                    },
                    None => Some(ai)
                }
            },
            None => self.1.intersect(ray)
        }
    }
}

fn main() {
    let scene = (
        Sphere {
            center: Point3::new(1.2, 0.0, 5.0),
            radius: 0.3
        },
        Sphere {
            center: Point3::new(1.5, 0.0, 3.5),
            radius: 0.35
        }
    );

    let imgx = 800;
    let imgy = 800;

    let scalex = 4.0 / imgx as f32;
    let scaley = 4.0 / imgy as f32;

    // Create a new ImgBuf with width: imgx and height: imgy
    let mut imgbuf = image::ImageBuffer::new(imgx, imgy);

    // Iterate over the coordiantes and pixels of the image
    for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
        let cy = y as f32 * scaley - 2.0;
        let cx = x as f32 * scalex - 2.0;

        let ray = Ray3 {
            start: Point3::new(0., 0., -8.0),
            dir: Vec3::new(cx, cy, 8.0)
        };

        let value: f32 = match scene.intersect(ray) {
            Some(intersection) => {
                let scale = -(intersection.normal.mag2() * ray.dir.mag2()).sqrt();
                intersection.normal.dot(ray.dir) / scale
            },
            None => 0.
        };

        // Create an 8bit pixel of type Luma and value i
        // and assign in to the pixel at position (x, y)
        *pixel = image::Luma([(value*255.) as u8]);
    }

    // Save the image as “out.png”
    let ref mut fout = File::create(&Path::new("out.png")).unwrap();

    // We must indicate the image’s color type and what format to save as
    let _ = image::ImageLuma8(imgbuf).save(fout, image::PNG);
}
<commit_msg>Added plane support<commit_after>//!A raytracer.
#![feature(path, io)]
extern crate image;

use std::old_io::File;
use std::num::Float;

use point::Point3;
use vec::Vec3;

mod vec;
mod point;

#[derive(Copy)]
struct Ray3 {
    start: Point3,
    dir: Vec3
}

struct Intersection {
    time: f32,
    normal: Vec3
}

trait Scene {
    fn intersect(&self, ray: Ray3) -> Option<Intersection>;
}

struct Sphere {
    center: Point3,
    radius: f32
}

impl Scene for Sphere {
    fn intersect(&self, ray: Ray3) -> Option<Intersection> {
        let offset = ray.start - self.center;

        let a = ray.dir.mag2();
        let b = 2. * offset.dot(ray.dir);
        let c = offset.mag2() - self.radius*self.radius;

        let descrim = b*b - 4.*a*c;
        if descrim > 0. {
            let t1 = (-b - descrim.sqrt()) / (2. * a);
            let t2 = (-b + descrim.sqrt()) / (2. * a);
            if t1 > 0. {
                let normal = ray.start + ray.dir * t1 - self.center;
                Some(Intersection { time: t1, normal: normal })
            } else if t2 > 0. {
                let normal = ray.start + ray.dir * t2 - self.center;
                Some(Intersection { time: t2, normal: normal })
            } else {
                None
            }
        } else {
            None
        }
    }
}

struct Plane {
    origin: Point3,
    normal: Vec3
}

impl Scene for Plane {
    fn intersect(&self, ray: Ray3) -> Option<Intersection> {
        let divisor = ray.dir.dot(self.normal);
        if divisor == 0. {
            None
        } else {
            let offset = ray.start - self.origin;
            let time = -offset.dot(self.normal) / divisor;
            if time > 0. {
                Some(Intersection { time: time, normal: self.normal })
            } else {
                None
            }
        }
    }
}

impl<A: Scene, B: Scene> Scene for (A, B) {
    fn intersect(&self, ray: Ray3) -> Option<Intersection> {
        match self.0.intersect(ray) {
            Some(ai) => {
                match self.1.intersect(ray) {
                    Some(bi) => if ai.time < bi.time {
                        Some(ai)
                    } else {
                        Some(bi)
                    },
                    None => Some(ai)
                }
            },
            None => self.1.intersect(ray)
        }
    }
}

fn main() {
    let scene = (
        (Sphere {
            center: Point3::new(1.2, 0.0, 5.0),
            radius: 0.3
        },
        Sphere {
            center: Point3::new(1.5, 0.0, 3.5),
            radius: 0.35
        }),
        (Plane {
            origin: Point3::new(0.0, 0.0, 8.0),
            normal: Vec3::new(2.0, 0.0, -1.0)
        },
        Plane {
            origin: Point3::new(0.0, 0.0, 8.0),
            normal: Vec3::new(-1.0, 0.0, -2.0)
        })
    );

    let imgx = 800;
    let imgy = 800;

    let scalex = 4.0 / imgx as f32;
    let scaley = 4.0 / imgy as f32;

    // Create a new ImgBuf with width: imgx and height: imgy
    let mut imgbuf = image::ImageBuffer::new(imgx, imgy);

    // Iterate over the coordiantes and pixels of the image
    for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
        let cy = y as f32 * scaley - 2.0;
        let cx = x as f32 * scalex - 2.0;

        let ray = Ray3 {
            start: Point3::new(0., 0., -8.0),
            dir: Vec3::new(cx, cy, 8.0)
        };

        let value: f32 = match scene.intersect(ray) {
            Some(intersection) => {
                let scale = -(intersection.normal.mag2() * ray.dir.mag2()).sqrt();
                intersection.normal.dot(ray.dir) / scale
            },
            None => 0.
        };

        // Create an 8bit pixel of type Luma and value i
        // and assign in to the pixel at position (x, y)
        *pixel = image::Luma([(value*255.) as u8]);
    }

    // Save the image as “out.png”
    let ref mut fout = File::create(&Path::new("out.png")).unwrap();

    // We must indicate the image’s color type and what format to save as
    let _ = image::ImageLuma8(imgbuf).save(fout, image::PNG);
}
<|endoftext|>