<commit_before>mod app;
mod error;
mod exec;
mod exit_codes;
mod filesystem;
mod filetypes;
mod filter;
mod options;
mod output;
mod regex_helper;
mod walk;

use std::env;
use std::path::{Path, PathBuf};
use std::process;
use std::sync::Arc;
use std::time;

use anyhow::{anyhow, Context, Result};
use atty::Stream;
use globset::GlobBuilder;
use lscolors::LsColors;
use regex::bytes::{RegexBuilder, RegexSetBuilder};

use crate::error::print_error;
use crate::exec::CommandTemplate;
use crate::exit_codes::ExitCode;
use crate::filetypes::FileTypes;
#[cfg(unix)]
use crate::filter::OwnerFilter;
use crate::filter::{SizeFilter, TimeFilter};
use crate::options::Options;
use crate::regex_helper::pattern_has_uppercase_char;

// We use jemalloc for performance reasons, see https://github.com/sharkdp/fd/pull/481
// FIXME: re-enable jemalloc on macOS, see comment in Cargo.toml file for more infos
#[cfg(all(not(windows), not(target_os = "macos"), not(target_env = "musl")))]
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

fn run() -> Result<ExitCode> {
    let matches = app::build_app().get_matches_from(env::args_os());

    // Set the current working directory of the process
    if let Some(base_directory) = matches.value_of_os("base-directory") {
        let base_directory = Path::new(base_directory);
        if !filesystem::is_dir(base_directory) {
            return Err(anyhow!(
                "The '--base-directory' path '{}' is not a directory.",
                base_directory.to_string_lossy()
            ));
        }
        env::set_current_dir(base_directory).with_context(|| {
            format!(
                "Could not set '{}' as the current working directory.",
                base_directory.to_string_lossy()
            )
        })?;
    }

    let current_directory = Path::new(".");
    if !filesystem::is_dir(current_directory) {
        return Err(anyhow!(
            "Could not retrieve current directory (has it been deleted?)."
        ));
    }

    // Get the search pattern
    let pattern = matches
        .value_of_os("pattern")
        .map(|p| {
            p.to_str()
                .ok_or_else(|| anyhow!("The search pattern includes invalid UTF-8 sequences."))
        })
        .transpose()?
        .unwrap_or("");

    // Get one or more root directories to search.
    let passed_arguments = matches
        .values_of_os("path")
        .or_else(|| matches.values_of_os("search-path"));

    let mut search_paths = if let Some(paths) = passed_arguments {
        let mut directories = vec![];
        for path in paths {
            let path_buffer = PathBuf::from(path);
            if filesystem::is_dir(&path_buffer) {
                directories.push(path_buffer);
            } else {
                print_error(format!(
                    "Search path '{}' is not a directory.",
                    path_buffer.to_string_lossy()
                ));
            }
        }

        directories
    } else {
        vec![current_directory.to_path_buf()]
    };

    // Check if we have no valid search paths.
    if search_paths.is_empty() {
        return Err(anyhow!("No valid search paths given."));
    }

    if matches.is_present("absolute-path") {
        search_paths = search_paths
            .iter()
            .map(|path_buffer| {
                path_buffer
                    .canonicalize()
                    .and_then(|pb| filesystem::absolute_path(pb.as_path()))
                    .unwrap()
            })
            .collect();
    }

    // Detect if the user accidentally supplied a path instead of a search pattern
    if !matches.is_present("full-path")
        && pattern.contains(std::path::MAIN_SEPARATOR)
        && filesystem::is_dir(Path::new(pattern))
    {
        return Err(anyhow!(
            "The search pattern '{pattern}' contains a path-separation character ('{sep}') \
             and will not lead to any search results.\n\n\
             If you want to search for all files inside the '{pattern}' directory, use a match-all pattern:\n\n  \
             fd . '{pattern}'\n\n\
             Instead, if you want your pattern to match the full file path, use:\n\n  \
             fd --full-path '{pattern}'",
            pattern = pattern,
            sep = std::path::MAIN_SEPARATOR,
        ));
    }

    let pattern_regex = if matches.is_present("glob") && !pattern.is_empty() {
        let glob = GlobBuilder::new(pattern).literal_separator(true).build()?;
        glob.regex().to_owned()
    } else if matches.is_present("fixed-strings") {
        // Treat pattern as literal string if '--fixed-strings' is used
        regex::escape(pattern)
    } else {
        String::from(pattern)
    };

    // The search will be case-sensitive if the command line flag is set or
    // if the pattern has an uppercase character (smart case).
    let case_sensitive = !matches.is_present("ignore-case")
        && (matches.is_present("case-sensitive") || pattern_has_uppercase_char(&pattern_regex));

    let interactive_terminal = atty::is(Stream::Stdout);
    let colored_output = match matches.value_of("color") {
        Some("always") => true,
        Some("never") => false,
        _ => env::var_os("NO_COLOR").is_none() && interactive_terminal,
    };

    let path_separator = matches.value_of("path-separator").map(|str| str.to_owned());

    #[cfg(windows)]
    let colored_output = colored_output && ansi_term::enable_ansi_support().is_ok();

    let ls_colors = if colored_output {
        Some(LsColors::from_env().unwrap_or_default())
    } else {
        None
    };

    let command = if let Some(args) = matches.values_of("exec") {
        Some(CommandTemplate::new(args))
    } else if let Some(args) = matches.values_of("exec-batch") {
        Some(CommandTemplate::new_batch(args)?)
    } else if matches.is_present("list-details") {
        let color = matches.value_of("color").unwrap_or("auto");
        let color_arg = ["--color=", color].concat();

        #[allow(unused)]
        let gnu_ls = |command_name| {
            vec![
                command_name,
                "-l",               // long listing format
                "--human-readable", // human readable file sizes
                "--directory",      // list directories themselves, not their contents
                &color_arg,
            ]
        };

        let cmd: Vec<&str> = if cfg!(unix) {
            if !cfg!(any(
                target_os = "macos",
                target_os = "dragonfly",
                target_os = "freebsd",
                target_os = "netbsd",
                target_os = "openbsd"
            )) {
                // Assume ls is GNU ls
                gnu_ls("ls")
            } else {
                // MacOS, DragonFlyBSD, FreeBSD
                use std::process::{Command, Stdio};

                // Use GNU ls, if available (support for --color=auto, better LS_COLORS support)
                let gnu_ls_exists = Command::new("gls")
                    .arg("--version")
                    .stdout(Stdio::null())
                    .stderr(Stdio::null())
                    .status()
                    .is_ok();

                if gnu_ls_exists {
                    gnu_ls("gls")
                } else {
                    let mut cmd = vec![
                        "ls", // BSD version of ls
                        "-l", // long listing format
                        "-h", // '--human-readable' is not available, '-h' is
                        "-d", // '--directory' is not available, but '-d' is
                    ];

                    if !cfg!(any(target_os = "netbsd", target_os = "openbsd")) && colored_output {
                        // -G is not available in NetBSD's and OpenBSD's ls
                        cmd.push("-G");
                    }

                    cmd
                }
            }
        } else if cfg!(windows) {
            use std::process::{Command, Stdio};

            // Use GNU ls, if available
            let gnu_ls_exists = Command::new("ls")
                .arg("--version")
                .stdout(Stdio::null())
                .stderr(Stdio::null())
                .status()
                .is_ok();

            if gnu_ls_exists {
                gnu_ls("ls")
            } else {
                return Err(anyhow!(
                    "'fd --list-details' is not supported on Windows unless GNU 'ls' is installed."
                ));
            }
        } else {
            return Err(anyhow!(
                "'fd --list-details' is not supported on this platform."
            ));
        };

        Some(CommandTemplate::new_batch(&cmd).unwrap())
    } else {
        None
    };

    let size_limits = if let Some(vs) = matches.values_of("size") {
        vs.map(|sf| {
            SizeFilter::from_string(sf)
                .ok_or_else(|| anyhow!("'{}' is not a valid size constraint. See 'fd --help'.", sf))
        })
        .collect::<Result<Vec<_>>>()?
    } else {
        vec![]
    };

    let now = time::SystemTime::now();
    let mut time_constraints: Vec<TimeFilter> = Vec::new();
    if let Some(t) = matches.value_of("changed-within") {
        if let Some(f) = TimeFilter::after(&now, t) {
            time_constraints.push(f);
        } else {
            return Err(anyhow!(
                "'{}' is not a valid date or duration. See 'fd --help'.",
                t
            ));
        }
    }
    if let Some(t) = matches.value_of("changed-before") {
        if let Some(f) = TimeFilter::before(&now, t) {
            time_constraints.push(f);
        } else {
            return Err(anyhow!(
                "'{}' is not a valid date or duration. See 'fd --help'.",
                t
            ));
        }
    }

    #[cfg(unix)]
    let owner_constraint = if let Some(s) = matches.value_of("owner") {
        OwnerFilter::from_string(s)?
    } else {
        None
    };

    let config = Options {
        case_sensitive,
        search_full_path: matches.is_present("full-path"),
        ignore_hidden: !(matches.is_present("hidden")
            || matches.occurrences_of("rg-alias-hidden-ignore") >= 2),
        read_fdignore: !(matches.is_present("no-ignore")
            || matches.is_present("rg-alias-hidden-ignore")),
        read_vcsignore: !(matches.is_present("no-ignore")
            || matches.is_present("rg-alias-hidden-ignore")
            || matches.is_present("no-ignore-vcs")),
        read_global_ignore: !(matches.is_present("no-ignore")
            || matches.is_present("rg-alias-hidden-ignore")
            || matches.is_present("no-global-ignore-file")),
        follow_links: matches.is_present("follow"),
        one_file_system: matches.is_present("one-file-system"),
        null_separator: matches.is_present("null_separator"),
        max_depth: matches
            .value_of("max-depth")
            .or_else(|| matches.value_of("rg-depth"))
            .or_else(|| matches.value_of("exact-depth"))
            .and_then(|n| usize::from_str_radix(n, 10).ok()),
        min_depth: matches
            .value_of("min-depth")
            .or_else(|| matches.value_of("exact-depth"))
            .and_then(|n| usize::from_str_radix(n, 10).ok()),
        threads: std::cmp::max(
            matches
                .value_of("threads")
                .and_then(|n| usize::from_str_radix(n, 10).ok())
                .unwrap_or_else(num_cpus::get),
            1,
        ),
        max_buffer_time: matches
            .value_of("max-buffer-time")
            .and_then(|n| u64::from_str_radix(n, 10).ok())
            .map(time::Duration::from_millis),
        ls_colors,
        interactive_terminal,
        file_types: matches.values_of("file-type").map(|values| {
            let mut file_types = FileTypes::default();
            for value in values {
                match value {
                    "f" | "file" => file_types.files = true,
                    "d" | "directory" => file_types.directories = true,
                    "l" | "symlink" => file_types.symlinks = true,
                    "x" | "executable" => {
                        file_types.executables_only = true;
                        file_types.files = true;
                    }
                    "e" | "empty" => file_types.empty_only = true,
                    "s" | "socket" => file_types.sockets = true,
                    "p" | "pipe" => file_types.pipes = true,
                    _ => unreachable!(),
                }
            }

            // If only 'empty' was specified, search for both files and directories:
            if file_types.empty_only && !(file_types.files || file_types.directories) {
                file_types.files = true;
                file_types.directories = true;
            }

            file_types
        }),
        extensions: matches
            .values_of("extension")
            .map(|exts| {
                let patterns = exts
                    .map(|e| e.trim_start_matches('.'))
                    .map(|e| format!(r".\.{}$", regex::escape(e)));
                RegexSetBuilder::new(patterns)
                    .case_insensitive(true)
                    .build()
            })
            .transpose()?,
        command: command.map(Arc::new),
        exclude_patterns: matches
            .values_of("exclude")
            .map(|v| v.map(|p| String::from("!") + p).collect())
            .unwrap_or_else(|| vec![]),
        ignore_files: matches
            .values_of("ignore-file")
            .map(|vs| vs.map(PathBuf::from).collect())
            .unwrap_or_else(|| vec![]),
        size_constraints: size_limits,
        time_constraints,
        #[cfg(unix)]
        owner_constraint,
        show_filesystem_errors: matches.is_present("show-errors"),
        path_separator,
        max_results: matches
            .value_of("max-results")
            .and_then(|n| usize::from_str_radix(n, 10).ok())
            .filter(|&n| n != 0)
            .or_else(|| {
                if matches.is_present("max-one-result") {
                    Some(1)
                } else {
                    None
                }
            }),
    };

    let re = RegexBuilder::new(&pattern_regex)
        .case_insensitive(!config.case_sensitive)
        .dot_matches_new_line(true)
        .build()
        .map_err(|e| {
            anyhow!(
                "{}\n\nNote: You can use the '--fixed-strings' option to search for a \
                 literal string instead of a regular expression. Alternatively, you can \
                 also use the '--glob' option to match on a glob pattern.",
                e.to_string()
            )
        })?;

    walk::scan(&search_paths, Arc::new(re), Arc::new(config))
}

fn main() {
    let result = run();
    match result {
        Ok(exit_code) => {
            process::exit(exit_code.into());
        }
        Err(err) => {
            eprintln!("[fd error]: {}", err);
            process::exit(ExitCode::GeneralError.into());
        }
    }
}
<commit_msg>Windows: Always enable colors if --color=always is set<commit_after>mod app;
mod error;
mod exec;
mod exit_codes;
mod filesystem;
mod filetypes;
mod filter;
mod options;
mod output;
mod regex_helper;
mod walk;

use std::env;
use std::path::{Path, PathBuf};
use std::process;
use std::sync::Arc;
use std::time;

use anyhow::{anyhow, Context, Result};
use atty::Stream;
use globset::GlobBuilder;
use lscolors::LsColors;
use regex::bytes::{RegexBuilder, RegexSetBuilder};

use crate::error::print_error;
use crate::exec::CommandTemplate;
use crate::exit_codes::ExitCode;
use crate::filetypes::FileTypes;
#[cfg(unix)]
use crate::filter::OwnerFilter;
use crate::filter::{SizeFilter, TimeFilter};
use crate::options::Options;
use crate::regex_helper::pattern_has_uppercase_char;

// We use jemalloc for performance reasons, see https://github.com/sharkdp/fd/pull/481
// FIXME: re-enable jemalloc on macOS, see comment in Cargo.toml file for more infos
#[cfg(all(not(windows), not(target_os = "macos"), not(target_env = "musl")))]
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

fn run() -> Result<ExitCode> {
    let matches = app::build_app().get_matches_from(env::args_os());

    // Set the current working directory of the process
    if let Some(base_directory) = matches.value_of_os("base-directory") {
        let base_directory = Path::new(base_directory);
        if !filesystem::is_dir(base_directory) {
            return Err(anyhow!(
                "The '--base-directory' path '{}' is not a directory.",
                base_directory.to_string_lossy()
            ));
        }
        env::set_current_dir(base_directory).with_context(|| {
            format!(
                "Could not set '{}' as the current working directory.",
                base_directory.to_string_lossy()
            )
        })?;
    }

    let current_directory = Path::new(".");
    if !filesystem::is_dir(current_directory) {
        return Err(anyhow!(
            "Could not retrieve current directory (has it been deleted?)."
        ));
    }

    // Get the search pattern
    let pattern = matches
        .value_of_os("pattern")
        .map(|p| {
            p.to_str()
                .ok_or_else(|| anyhow!("The search pattern includes invalid UTF-8 sequences."))
        })
        .transpose()?
        .unwrap_or("");

    // Get one or more root directories to search.
    let passed_arguments = matches
        .values_of_os("path")
        .or_else(|| matches.values_of_os("search-path"));

    let mut search_paths = if let Some(paths) = passed_arguments {
        let mut directories = vec![];
        for path in paths {
            let path_buffer = PathBuf::from(path);
            if filesystem::is_dir(&path_buffer) {
                directories.push(path_buffer);
            } else {
                print_error(format!(
                    "Search path '{}' is not a directory.",
                    path_buffer.to_string_lossy()
                ));
            }
        }

        directories
    } else {
        vec![current_directory.to_path_buf()]
    };

    // Check if we have no valid search paths.
    if search_paths.is_empty() {
        return Err(anyhow!("No valid search paths given."));
    }

    if matches.is_present("absolute-path") {
        search_paths = search_paths
            .iter()
            .map(|path_buffer| {
                path_buffer
                    .canonicalize()
                    .and_then(|pb| filesystem::absolute_path(pb.as_path()))
                    .unwrap()
            })
            .collect();
    }

    // Detect if the user accidentally supplied a path instead of a search pattern
    if !matches.is_present("full-path")
        && pattern.contains(std::path::MAIN_SEPARATOR)
        && filesystem::is_dir(Path::new(pattern))
    {
        return Err(anyhow!(
            "The search pattern '{pattern}' contains a path-separation character ('{sep}') \
             and will not lead to any search results.\n\n\
             If you want to search for all files inside the '{pattern}' directory, use a match-all pattern:\n\n  \
             fd . '{pattern}'\n\n\
             Instead, if you want your pattern to match the full file path, use:\n\n  \
             fd --full-path '{pattern}'",
            pattern = pattern,
            sep = std::path::MAIN_SEPARATOR,
        ));
    }

    let pattern_regex = if matches.is_present("glob") && !pattern.is_empty() {
        let glob = GlobBuilder::new(pattern).literal_separator(true).build()?;
        glob.regex().to_owned()
    } else if matches.is_present("fixed-strings") {
        // Treat pattern as literal string if '--fixed-strings' is used
        regex::escape(pattern)
    } else {
        String::from(pattern)
    };

    // The search will be case-sensitive if the command line flag is set or
    // if the pattern has an uppercase character (smart case).
    let case_sensitive = !matches.is_present("ignore-case")
        && (matches.is_present("case-sensitive") || pattern_has_uppercase_char(&pattern_regex));

    #[cfg(windows)]
    let ansi_colors_support = ansi_term::enable_ansi_support().is_ok();

    #[cfg(not(windows))]
    let ansi_colors_support = true;

    let interactive_terminal = atty::is(Stream::Stdout);
    let colored_output = match matches.value_of("color") {
        Some("always") => true,
        Some("never") => false,
        _ => ansi_colors_support && env::var_os("NO_COLOR").is_none() && interactive_terminal,
    };

    let path_separator = matches.value_of("path-separator").map(|str| str.to_owned());

    let ls_colors = if colored_output {
        Some(LsColors::from_env().unwrap_or_default())
    } else {
        None
    };

    let command = if let Some(args) = matches.values_of("exec") {
        Some(CommandTemplate::new(args))
    } else if let Some(args) = matches.values_of("exec-batch") {
        Some(CommandTemplate::new_batch(args)?)
    } else if matches.is_present("list-details") {
        let color = matches.value_of("color").unwrap_or("auto");
        let color_arg = ["--color=", color].concat();

        #[allow(unused)]
        let gnu_ls = |command_name| {
            vec![
                command_name,
                "-l",               // long listing format
                "--human-readable", // human readable file sizes
                "--directory",      // list directories themselves, not their contents
                &color_arg,
            ]
        };

        let cmd: Vec<&str> = if cfg!(unix) {
            if !cfg!(any(
                target_os = "macos",
                target_os = "dragonfly",
                target_os = "freebsd",
                target_os = "netbsd",
                target_os = "openbsd"
            )) {
                // Assume ls is GNU ls
                gnu_ls("ls")
            } else {
                // MacOS, DragonFlyBSD, FreeBSD
                use std::process::{Command, Stdio};

                // Use GNU ls, if available (support for --color=auto, better LS_COLORS support)
                let gnu_ls_exists = Command::new("gls")
                    .arg("--version")
                    .stdout(Stdio::null())
                    .stderr(Stdio::null())
                    .status()
                    .is_ok();

                if gnu_ls_exists {
                    gnu_ls("gls")
                } else {
                    let mut cmd = vec![
                        "ls", // BSD version of ls
                        "-l", // long listing format
                        "-h", // '--human-readable' is not available, '-h' is
                        "-d", // '--directory' is not available, but '-d' is
                    ];

                    if !cfg!(any(target_os = "netbsd", target_os = "openbsd")) && colored_output {
                        // -G is not available in NetBSD's and OpenBSD's ls
                        cmd.push("-G");
                    }

                    cmd
                }
            }
        } else if cfg!(windows) {
            use std::process::{Command, Stdio};

            // Use GNU ls, if available
            let gnu_ls_exists = Command::new("ls")
                .arg("--version")
                .stdout(Stdio::null())
                .stderr(Stdio::null())
                .status()
                .is_ok();

            if gnu_ls_exists {
                gnu_ls("ls")
            } else {
                return Err(anyhow!(
                    "'fd --list-details' is not supported on Windows unless GNU 'ls' is installed."
                ));
            }
        } else {
            return Err(anyhow!(
                "'fd --list-details' is not supported on this platform."
            ));
        };

        Some(CommandTemplate::new_batch(&cmd).unwrap())
    } else {
        None
    };

    let size_limits = if let Some(vs) = matches.values_of("size") {
        vs.map(|sf| {
            SizeFilter::from_string(sf)
                .ok_or_else(|| anyhow!("'{}' is not a valid size constraint. See 'fd --help'.", sf))
        })
        .collect::<Result<Vec<_>>>()?
    } else {
        vec![]
    };

    let now = time::SystemTime::now();
    let mut time_constraints: Vec<TimeFilter> = Vec::new();
    if let Some(t) = matches.value_of("changed-within") {
        if let Some(f) = TimeFilter::after(&now, t) {
            time_constraints.push(f);
        } else {
            return Err(anyhow!(
                "'{}' is not a valid date or duration. See 'fd --help'.",
                t
            ));
        }
    }
    if let Some(t) = matches.value_of("changed-before") {
        if let Some(f) = TimeFilter::before(&now, t) {
            time_constraints.push(f);
        } else {
            return Err(anyhow!(
                "'{}' is not a valid date or duration. See 'fd --help'.",
                t
            ));
        }
    }

    #[cfg(unix)]
    let owner_constraint = if let Some(s) = matches.value_of("owner") {
        OwnerFilter::from_string(s)?
    } else {
        None
    };

    let config = Options {
        case_sensitive,
        search_full_path: matches.is_present("full-path"),
        ignore_hidden: !(matches.is_present("hidden")
            || matches.occurrences_of("rg-alias-hidden-ignore") >= 2),
        read_fdignore: !(matches.is_present("no-ignore")
            || matches.is_present("rg-alias-hidden-ignore")),
        read_vcsignore: !(matches.is_present("no-ignore")
            || matches.is_present("rg-alias-hidden-ignore")
            || matches.is_present("no-ignore-vcs")),
        read_global_ignore: !(matches.is_present("no-ignore")
            || matches.is_present("rg-alias-hidden-ignore")
            || matches.is_present("no-global-ignore-file")),
        follow_links: matches.is_present("follow"),
        one_file_system: matches.is_present("one-file-system"),
        null_separator: matches.is_present("null_separator"),
        max_depth: matches
            .value_of("max-depth")
            .or_else(|| matches.value_of("rg-depth"))
            .or_else(|| matches.value_of("exact-depth"))
            .and_then(|n| usize::from_str_radix(n, 10).ok()),
        min_depth: matches
            .value_of("min-depth")
            .or_else(|| matches.value_of("exact-depth"))
            .and_then(|n| usize::from_str_radix(n, 10).ok()),
        threads: std::cmp::max(
            matches
                .value_of("threads")
                .and_then(|n| usize::from_str_radix(n, 10).ok())
                .unwrap_or_else(num_cpus::get),
            1,
        ),
        max_buffer_time: matches
            .value_of("max-buffer-time")
            .and_then(|n| u64::from_str_radix(n, 10).ok())
            .map(time::Duration::from_millis),
        ls_colors,
        interactive_terminal,
        file_types: matches.values_of("file-type").map(|values| {
            let mut file_types = FileTypes::default();
            for value in values {
                match value {
                    "f" | "file" => file_types.files = true,
                    "d" | "directory" => file_types.directories = true,
                    "l" | "symlink" => file_types.symlinks = true,
                    "x" | "executable" => {
                        file_types.executables_only = true;
                        file_types.files = true;
                    }
                    "e" | "empty" => file_types.empty_only = true,
                    "s" | "socket" => file_types.sockets = true,
                    "p" | "pipe" => file_types.pipes = true,
                    _ => unreachable!(),
                }
            }

            // If only 'empty' was specified, search for both files and directories:
            if file_types.empty_only && !(file_types.files || file_types.directories) {
                file_types.files = true;
                file_types.directories = true;
            }

            file_types
        }),
        extensions: matches
            .values_of("extension")
            .map(|exts| {
                let patterns = exts
                    .map(|e| e.trim_start_matches('.'))
                    .map(|e| format!(r".\.{}$", regex::escape(e)));
                RegexSetBuilder::new(patterns)
                    .case_insensitive(true)
                    .build()
            })
            .transpose()?,
        command: command.map(Arc::new),
        exclude_patterns: matches
            .values_of("exclude")
            .map(|v| v.map(|p| String::from("!") + p).collect())
            .unwrap_or_else(|| vec![]),
        ignore_files: matches
            .values_of("ignore-file")
            .map(|vs| vs.map(PathBuf::from).collect())
            .unwrap_or_else(|| vec![]),
        size_constraints: size_limits,
        time_constraints,
        #[cfg(unix)]
        owner_constraint,
        show_filesystem_errors: matches.is_present("show-errors"),
        path_separator,
        max_results: matches
            .value_of("max-results")
            .and_then(|n| usize::from_str_radix(n, 10).ok())
            .filter(|&n| n != 0)
            .or_else(|| {
                if matches.is_present("max-one-result") {
                    Some(1)
                } else {
                    None
                }
            }),
    };

    let re = RegexBuilder::new(&pattern_regex)
        .case_insensitive(!config.case_sensitive)
        .dot_matches_new_line(true)
        .build()
        .map_err(|e| {
            anyhow!(
                "{}\n\nNote: You can use the '--fixed-strings' option to search for a \
                 literal string instead of a regular expression. Alternatively, you can \
                 also use the '--glob' option to match on a glob pattern.",
                e.to_string()
            )
        })?;

    walk::scan(&search_paths, Arc::new(re), Arc::new(config))
}

fn main() {
    let result = run();
    match result {
        Ok(exit_code) => {
            process::exit(exit_code.into());
        }
        Err(err) => {
            eprintln!("[fd error]: {}", err);
            process::exit(ExitCode::GeneralError.into());
        }
    }
}
<|endoftext|>


<commit_before>extern crate sdl2;

use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;

trait TinyRenderer {
    fn pixel(&mut self, Point, Color);
    fn line(&mut self, Point, Point, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, p: Point, c: Color) {
        let current_color = self.draw_color();

        self.set_draw_color(c);
        self.draw_point(p).unwrap();
        self.set_draw_color(current_color);
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let dx = (end.x() - start.x()).abs();
        let dy = (end.y() - start.y()).abs();

        let mut err = 0;
        let derr = dy;
        let mut y = start.y();

        for x in start.x() .. end.x() {
            self.draw_point(Point::new(x, y)).unwrap();
            err += derr;

            if 2 * err >= dx {
                y += 1;
                err -= dx;
            }
        }

        self.set_draw_color(current_color);
    }
}

fn main() {
    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", 800, 600)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();

    //Draw pixel
    renderer.pixel(Point::new(200, 200), Color::RGB(0, 255, 0));
    renderer.line(Point::new(250, 250), Point::new(385, 460), Color::RGB(0, 0, 255));

    renderer.present();

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        //code here
    }
}
<commit_msg>Improve dummy line drawing algorithm<commit_after>extern crate sdl2;

use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;
use std::cmp::Ordering;

trait TinyRenderer {
    fn pixel(&mut self, Point, Color);
    fn line(&mut self, Point, Point, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, p: Point, c: Color) {
        let current_color = self.draw_color();

        self.set_draw_color(c);
        self.draw_point(p).unwrap();
        self.set_draw_color(current_color);
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let mut x0 = start.x();
        let mut y0 = start.y();
        let mut x1 = end.x();
        let mut y1 = end.y();

        let steep = (y1 - y0).abs() > (x1 - x0).abs();

        if steep {
            std::mem::swap(&mut x0, &mut y0);
            std::mem::swap(&mut x1, &mut y1);
        }

        let reverse = x0 > x1;

        if reverse {
            std::mem::swap(&mut x0, &mut x1);
            std::mem::swap(&mut y0, &mut y1);
        }

        let dx = x1 - x0;
        let dy = (y1 - y0).abs();

        let mut err = dx / 2;
        let mut y = y0;
        let ystep = match y0.cmp(&y1) {
            Ordering::Less => 1,
            _ => -1
        };

        for x in x0..x1 {
            if steep {
                self.draw_point(Point::new(y, x)).unwrap();
            } else {
                self.draw_point(Point::new(x, y)).unwrap();
            }

            err -= dy;

            if err < 0 {
                y += ystep;
                err += dx;
            }
        }

        self.set_draw_color(current_color);
    }
}

fn main() {
    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", 800, 600)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();

    //Draw pixel
    renderer.pixel(Point::new(200, 200), Color::RGB(0, 255, 0));
    renderer.line(Point::new(250, 250), Point::new(385, 460), Color::RGB(0, 0, 255));
    renderer.line(Point::new(250, 250), Point::new(91, 0), Color::RGB(0, 255, 255));
    renderer.line(Point::new(250, 250), Point::new(385, 0), Color::RGB(255, 0, 255));

    renderer.present();

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        //code here
    }
}
<|endoftext|>


<commit_before>//
// Copyright (c) Pirmin Kalberer. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//

#[macro_use]
extern crate log;
extern crate env_logger;
extern crate toml;
#[macro_use] extern crate nickel;
extern crate rustc_serialize;
#[macro_use] extern crate hyper;
extern crate r2d2;
extern crate r2d2_postgres;
extern crate postgres;
extern crate postgis;
extern crate protobuf;
extern crate clap;
extern crate time;
extern crate flate2;
extern crate pbr;

pub mod core;
mod datasource;
pub mod mvt;
mod service;
mod cache;
mod webserver;

use core::grid::Extent;
use clap::{App, SubCommand, ArgMatches};
use std::env;
use std::process;
use log::{LogRecord, LogLevelFilter};
use env_logger::LogBuilder;

fn init_logger() {
    let format = |record: &LogRecord| {
        let t = time::now();
        format!("{}.{:03} {} {}",
            time::strftime("%Y-%m-%d %H:%M:%S", &t).unwrap(),
            t.tm_nsec / 1000_000,
            record.level(),
            record.args()
        )
    };

    let mut builder = LogBuilder::new();
    builder.format(format);

    match env::var("RUST_LOG") {
        Result::Ok(val) => { builder.parse(&val); },
        // Set log level to info by default
        Result::Err(_) => { builder.filter(None, LogLevelFilter::Info); }
    }

    builder.init().unwrap();
}

fn generate(args: &ArgMatches) {
    let (mut service, config) = webserver::server::service_from_args(args);
    let _ = config.lookup("cache.file.base")
        .ok_or("Missing configuration entry base in [cache.file]".to_string())
        .unwrap_or_else(|err| {
            println!("Error reading configuration - {} ", err);
            process::exit(1)
        });
    let tileset = args.value_of("tileset");
    let minzoom = args.value_of("minzoom").map(|s| s.parse::<u8>().unwrap());
    let maxzoom = args.value_of("maxzoom").map(|s| s.parse::<u8>().unwrap());
    let extent = args.values_of("extent").map(|vals| {
        let arr: Vec<f64> = vals.map(|v| v.parse().unwrap()).collect();
        Extent { minx: arr[0], miny: arr[1], maxx: arr[2], maxy: arr[3] }
    });
    let nodes = args.value_of("nodes").map(|s| s.parse::<u8>().unwrap());
    let nodeno = args.value_of("nodeno").map(|s| s.parse::<u8>().unwrap());
    let progress = args.value_of("progress").map_or(true, |s| s.parse::<bool>().unwrap());
    service.prepare_feature_queries();
    service.generate(tileset, minzoom, maxzoom, extent, nodes, nodeno, progress);
}

fn main() {
    init_logger();

    // http://kbknapp.github.io/clap-rs/clap/
    let mut app = App::new("t_rex")
                        .version("0.6.1")
                        .author("Pirmin Kalberer <pka@sourcepole.ch>")
                        .about("vector tile server specialized on publishing MVT tiles from a PostGIS database")
                        .subcommand(SubCommand::with_name("serve")
                            .args_from_usage("--dbconn=[SPEC] 'PostGIS connection postgresql://USER@HOST/DBNAME'
                                              --simplify=[true|false] 'Simplify geometries'
                                              --clip=[true|false] 'Clip geometries'
                                              --cache=[DIR] 'Use tile cache in DIR'
                                              -c, --config=[FILE] 'Load from custom config file'")
                            .about("Start web server and serve MVT vector tiles"))
                        .subcommand(SubCommand::with_name("genconfig")
                            .args_from_usage("--dbconn=[SPEC] 'PostGIS connection postgresql://USER@HOST/DBNAME'
                                              --simplify=[true|false] 'Simplify geometries'
                                              --clip=[true|false] 'Clip geometries'")
                            .about("Generate configuration template"))
                        .subcommand(SubCommand::with_name("generate")
                            .args_from_usage("-c, --config=<FILE> 'Load from custom config file'
                                              --tileset=[NAME] 'Tileset name'
                                              --minzoom=[LEVEL] 'Minimum zoom level'
                                              --maxzoom=[LEVEL] 'Maximum zoom level'
                                              --extent=[minx,miny,maxx,maxy] 'Extent of tiles'
                                              --nodes=[NUM] 'Number of generator nodes'
                                              --nodeno=[NUM] 'Number of this nodes (0 <= n < nodes)'
                                              --progress=[true|false] 'Show progress bar'")
                            .about("Generate tiles for cache"));

    match app.get_matches_from_safe_borrow(env::args()) { //app.get_matches() prohibits later call of app.print_help()
        Result::Err(e) => { println!("{}", e); },
        Result::Ok(matches) => {
            match matches.subcommand() {
                ("serve", Some(sub_m))     => webserver::server::webserver(sub_m),
                ("genconfig", Some(sub_m)) => println!("{}", webserver::server::gen_config(sub_m)),
                ("generate", Some(sub_m))  => generate(sub_m),
                _                          => { let _ = app.print_help(); println!(""); },
            }
        }
    }
}
<commit_msg>Support extents in the western hemisphere (#11)<commit_after>//
// Copyright (c) Pirmin Kalberer. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//

#[macro_use]
extern crate log;
extern crate env_logger;
extern crate toml;
#[macro_use] extern crate nickel;
extern crate rustc_serialize;
#[macro_use] extern crate hyper;
extern crate r2d2;
extern crate r2d2_postgres;
extern crate postgres;
extern crate postgis;
extern crate protobuf;
extern crate clap;
extern crate time;
extern crate flate2;
extern crate pbr;

pub mod core;
mod datasource;
pub mod mvt;
mod service;
mod cache;
mod webserver;

use core::grid::Extent;
use clap::{App, SubCommand, ArgMatches, AppSettings};
use std::env;
use std::process;
use log::{LogRecord, LogLevelFilter};
use env_logger::LogBuilder;

fn init_logger() {
    let format = |record: &LogRecord| {
        let t = time::now();
        format!("{}.{:03} {} {}",
            time::strftime("%Y-%m-%d %H:%M:%S", &t).unwrap(),
            t.tm_nsec / 1000_000,
            record.level(),
            record.args()
        )
    };

    let mut builder = LogBuilder::new();
    builder.format(format);

    match env::var("RUST_LOG") {
        Result::Ok(val) => { builder.parse(&val); },
        // Set log level to info by default
        Result::Err(_) => { builder.filter(None, LogLevelFilter::Info); }
    }

    builder.init().unwrap();
}

fn generate(args: &ArgMatches) {
    let (mut service, config) = webserver::server::service_from_args(args);
    let _ = config.lookup("cache.file.base")
        .ok_or("Missing configuration entry base in [cache.file]".to_string())
        .unwrap_or_else(|err| {
            println!("Error reading configuration - {} ", err);
            process::exit(1)
        });
    let tileset = args.value_of("tileset");
    let minzoom = args.value_of("minzoom").map(|s| s.parse::<u8>().unwrap());
    let maxzoom = args.value_of("maxzoom").map(|s| s.parse::<u8>().unwrap());
    let extent = args.values_of("extent").map(|vals| {
        let arr: Vec<f64> = vals.map(|v| v.parse().unwrap()).collect();
        Extent { minx: arr[0], miny: arr[1], maxx: arr[2], maxy: arr[3] }
    });
    let nodes = args.value_of("nodes").map(|s| s.parse::<u8>().unwrap());
    let nodeno = args.value_of("nodeno").map(|s| s.parse::<u8>().unwrap());
    let progress = args.value_of("progress").map_or(true, |s| s.parse::<bool>().unwrap());
    service.prepare_feature_queries();
    service.generate(tileset, minzoom, maxzoom, extent, nodes, nodeno, progress);
}

fn main() {
    init_logger();

    // http://kbknapp.github.io/clap-rs/clap/
    let mut app = App::new("t_rex")
                        .version("0.6.1")
                        .author("Pirmin Kalberer <pka@sourcepole.ch>")
                        .about("vector tile server specialized on publishing MVT tiles from a PostGIS database")
                        .subcommand(SubCommand::with_name("serve")
                            .args_from_usage("--dbconn=[SPEC] 'PostGIS connection postgresql://USER@HOST/DBNAME'
                                              --simplify=[true|false] 'Simplify geometries'
                                              --clip=[true|false] 'Clip geometries'
                                              --cache=[DIR] 'Use tile cache in DIR'
                                              -c, --config=[FILE] 'Load from custom config file'")
                            .about("Start web server and serve MVT vector tiles"))
                        .subcommand(SubCommand::with_name("genconfig")
                            .args_from_usage("--dbconn=[SPEC] 'PostGIS connection postgresql://USER@HOST/DBNAME'
                                              --simplify=[true|false] 'Simplify geometries'
                                              --clip=[true|false] 'Clip geometries'")
                            .about("Generate configuration template"))
                        .subcommand(SubCommand::with_name("generate")
                            .setting(AppSettings::AllowLeadingHyphen)
                            .args_from_usage("-c, --config=<FILE> 'Load from custom config file'
                                              --tileset=[NAME] 'Tileset name'
                                              --minzoom=[LEVEL] 'Minimum zoom level'
                                              --maxzoom=[LEVEL] 'Maximum zoom level'
                                              --extent=[minx,miny,maxx,maxy] 'Extent of tiles'
                                              --nodes=[NUM] 'Number of generator nodes'
                                              --nodeno=[NUM] 'Number of this nodes (0 <= n < nodes)'
                                              --progress=[true|false] 'Show progress bar'")
                            .about("Generate tiles for cache"));

    match app.get_matches_from_safe_borrow(env::args()) { //app.get_matches() prohibits later call of app.print_help()
        Result::Err(e) => { println!("{}", e); },
        Result::Ok(matches) => {
            match matches.subcommand() {
                ("serve", Some(sub_m))     => webserver::server::webserver(sub_m),
                ("genconfig", Some(sub_m)) => println!("{}", webserver::server::gen_config(sub_m)),
                ("generate", Some(sub_m))  => generate(sub_m),
                _                          => { let _ = app.print_help(); println!(""); },
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate toml;

use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::collections::BTreeMap;

fn strip_toolchain(name: &toml::Value) -> String {
    name.as_str().unwrap().split('-').nth(0).unwrap().to_string()
}

fn read_settings() -> (String, BTreeMap<String, toml::Value>) {
    let mut settings_path = env::home_dir().expect("Cannot get home directory");
    settings_path.push(".multirust/settings.toml");

    let mut file = File::open(&settings_path).expect("Error opening settings.toml file");

    let mut buffer = String::new();
    file.read_to_string(&mut buffer).expect("Error reading settings.toml");

    let value = toml::Parser::new(&buffer).parse().expect("Error parsing settings.toml");
    let default = value.get("default_toolchain")
        .expect("Did not found default_toolchain in settings.toml")
        .as_str()
        .unwrap();
    let overrides = value.get("overrides")
        .expect("Did not found overrides in settings.toml")
        .as_table()
        .unwrap();

    (default.to_owned(), overrides.to_owned())
}

fn main() {
    let cwd = env::current_dir().expect("Cannot get working directory");
    let cwd = cwd.to_str().expect("Cannot convert working directory to string");
    let (default, overrides) = read_settings();

    let toolchain = if let Some(toolchain) = overrides.get(cwd) {
        strip_toolchain(toolchain)
    } else {
        default
    };

    println!("{}", toolchain);
}
<commit_msg>follow rustup path change<commit_after>extern crate toml;

use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::collections::BTreeMap;

fn strip_toolchain(name: &toml::Value) -> String {
    name.as_str().unwrap().split('-').nth(0).unwrap().to_string()
}

fn read_settings() -> (String, BTreeMap<String, toml::Value>) {
    let mut settings_path = env::home_dir().expect("Cannot get home directory");
    settings_path.push(".rustup/settings.toml");

    let mut file = File::open(&settings_path).expect("Error opening settings.toml file");

    let mut buffer = String::new();
    file.read_to_string(&mut buffer).expect("Error reading settings.toml");

    let value = toml::Parser::new(&buffer).parse().expect("Error parsing settings.toml");
    let default = value.get("default_toolchain")
        .expect("Did not found default_toolchain in settings.toml")
        .as_str()
        .unwrap();
    let overrides = value.get("overrides")
        .expect("Did not found overrides in settings.toml")
        .as_table()
        .unwrap();

    (default.to_owned(), overrides.to_owned())
}

fn main() {
    let cwd = env::current_dir().expect("Cannot get working directory");
    let cwd = cwd.to_str().expect("Cannot convert working directory to string");
    let (default, overrides) = read_settings();

    let toolchain = if let Some(toolchain) = overrides.get(cwd) {
        strip_toolchain(toolchain)
    } else {
        default
    };

    println!("{}", toolchain);
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

extern crate czmq;
extern crate docopt;
extern crate rustc_serialize;
#[cfg(test)]
extern crate tempdir;
extern crate time;
extern crate zdaemon;

mod auth;
mod cert;
mod config;
mod error;
mod language;
mod project;

use auth::Auth;
use docopt::Docopt;
use error::Error;
use project::Project;
use std::{env, io};
use std::fmt::{Debug, Display};
use std::path::Path;
use std::process::exit;
use std::result::Result as StdResult;

const VERSION: &'static str = "0.2.1";

static USAGE: &'static str = "
Intecture CLI.

Usage:
  incli run [<arg>...]
  incli init [(-e | --example)] (<name> <lang>)
  incli host (add | delete | bootstrap) [(-s | --silent)] <hostname>
  incli host list
  incli user (add | delete) [(-s | --silent)] <username>
  incli user list
  incli (-h | --help)
  incli --version

Options:
  -e --example  Clone an example project.
  -h --help     Show this screen.
  -s --silent   Save private key instead of printing it.
  -v --verbose  Verbose output.
  --version     Show version.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_add: bool,
    cmd_bootstrap: bool,
    cmd_delete: bool,
    cmd_host: bool,
    cmd_init: bool,
    cmd_list: bool,
    cmd_run: bool,
    cmd_user: bool,
    flag_e: bool,
    flag_example: bool,
    flag_h: bool,
    flag_help: bool,
    flag_s: bool,
    flag_silent: bool,
    flag_v: bool,
    flag_verbose: bool,
    flag_version: bool,
    arg_arg: Vec<String>,
    arg_hostname: String,
    arg_lang: String,
    arg_name: String,
    arg_username: String,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("{}", VERSION);
    }
    else if args.cmd_run {
        let project = try_exit(Project::load(&mut env::current_dir().unwrap()), args.flag_v || args.flag_verbose);
        try_exit(project.run(&args.arg_arg), args.flag_v || args.flag_verbose);
    }
    else if args.cmd_init {
        try_exit(Project::create(&Path::new(&args.arg_name), &args.arg_lang, args.flag_e || args.flag_example), args.flag_v || args.flag_verbose);
    }
    else if args.cmd_host || args.cmd_user {
        let cert_type = if args.cmd_host { "host" } else { "user" };
        let name = if args.cmd_host { &args.arg_hostname } else { &args.arg_username };

        let auth = try_exit(Auth::new(&env::current_dir().unwrap()), args.flag_v || args.flag_verbose);

        if args.cmd_add {
            let cert = try_exit(auth.add(cert_type, name), args.flag_v || args.flag_verbose);
            if args.flag_s || args.flag_silent {
                try_exit(cert.save_secret(&format!("{}.crt", name)), args.flag_v || args.flag_verbose);
            } else {
                println!("Please distribute this certificate securely.

------------------------COPY BELOW THIS LINE-------------------------
{}
------------------------COPY ABOVE THIS LINE-------------------------", cert.secret());
            }
        }
        else if args.cmd_delete {
            if args.flag_s || args.flag_silent {
                try_exit(auth.delete(name), args.flag_v || args.flag_verbose);
            } else {
                println!("Are you sure you want to delete this certificate?");
                loop {
                    println!("Please enter [y/n]: ");
                    let mut input = String::new();
                    match io::stdin().read_line(&mut input) {
                        Ok(_) => match { input.as_ref() as &str }.trim() {
                            "y" => {
                                try_exit(auth.delete(name), args.flag_v || args.flag_verbose);
                                break;
                            },
                            "n" => break,
                            _ => (),
                        },
                        Err(e) => {
                            println!("Stdin error: {}", e);
                            exit(1);
                        },
                    }
                }
            }
        }
        else if args.cmd_list {
            let names = try_exit(auth.list(cert_type), args.flag_v || args.flag_verbose);

            for name in names {
                println!("{}", name);
            }
        }
        else if args.cmd_bootstrap && args.cmd_host {
            unimplemented!();
        }
    }
}

fn try_exit<T, E>(r: StdResult<T, E>, verbose: bool) -> T
    where E: Into<Error> + Debug + Display {
    if let Err(e) = r {
        println!("{}", e);

        if verbose {
            println!("{:?}", e);
        }

        exit(1);
    }

    r.unwrap()
}
<commit_msg>Docopt syntax cleanup<commit_after>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

extern crate czmq;
extern crate docopt;
extern crate rustc_serialize;
#[cfg(test)]
extern crate tempdir;
extern crate time;
extern crate zdaemon;

mod auth;
mod cert;
mod config;
mod error;
mod language;
mod project;

use auth::Auth;
use docopt::Docopt;
use error::Error;
use project::Project;
use std::{env, io};
use std::fmt::{Debug, Display};
use std::path::Path;
use std::process::exit;
use std::result::Result as StdResult;

const VERSION: &'static str = "0.2.1";

static USAGE: &'static str = "
Intecture CLI.

Usage:
  incli run [<arg>...]
  incli init [(-e | --example)] <name> <lang>
  incli host (add | delete | bootstrap) [(-s | --silent)] <hostname>
  incli host list
  incli user (add | delete) [(-s | --silent)] <username>
  incli user list
  incli (-h | --help)
  incli --version

Options:
  -e --example  Clone an example project.
  -h --help     Show this screen.
  -s --silent   Save private key instead of printing it.
  -v --verbose  Verbose output.
  --version     Show version.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_add: bool,
    cmd_bootstrap: bool,
    cmd_delete: bool,
    cmd_host: bool,
    cmd_init: bool,
    cmd_list: bool,
    cmd_run: bool,
    cmd_user: bool,
    flag_e: bool,
    flag_example: bool,
    flag_h: bool,
    flag_help: bool,
    flag_s: bool,
    flag_silent: bool,
    flag_v: bool,
    flag_verbose: bool,
    flag_version: bool,
    arg_arg: Vec<String>,
    arg_hostname: String,
    arg_lang: String,
    arg_name: String,
    arg_username: String,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("{}", VERSION);
    }
    else if args.cmd_run {
        let project = try_exit(Project::load(&mut env::current_dir().unwrap()), args.flag_v || args.flag_verbose);
        try_exit(project.run(&args.arg_arg), args.flag_v || args.flag_verbose);
    }
    else if args.cmd_init {
        try_exit(Project::create(&Path::new(&args.arg_name), &args.arg_lang, args.flag_e || args.flag_example), args.flag_v || args.flag_verbose);
    }
    else if args.cmd_host || args.cmd_user {
        let cert_type = if args.cmd_host { "host" } else { "user" };
        let name = if args.cmd_host { &args.arg_hostname } else { &args.arg_username };

        let auth = try_exit(Auth::new(&env::current_dir().unwrap()), args.flag_v || args.flag_verbose);

        if args.cmd_add {
            let cert = try_exit(auth.add(cert_type, name), args.flag_v || args.flag_verbose);
            if args.flag_s || args.flag_silent {
                try_exit(cert.save_secret(&format!("{}.crt", name)), args.flag_v || args.flag_verbose);
            } else {
                println!("Please distribute this certificate securely.

------------------------COPY BELOW THIS LINE-------------------------
{}
------------------------COPY ABOVE THIS LINE-------------------------", cert.secret());
            }
        }
        else if args.cmd_delete {
            if args.flag_s || args.flag_silent {
                try_exit(auth.delete(name), args.flag_v || args.flag_verbose);
            } else {
                println!("Are you sure you want to delete this certificate?");
                loop {
                    println!("Please enter [y/n]: ");
                    let mut input = String::new();
                    match io::stdin().read_line(&mut input) {
                        Ok(_) => match { input.as_ref() as &str }.trim() {
                            "y" => {
                                try_exit(auth.delete(name), args.flag_v || args.flag_verbose);
                                break;
                            },
                            "n" => break,
                            _ => (),
                        },
                        Err(e) => {
                            println!("Stdin error: {}", e);
                            exit(1);
                        },
                    }
                }
            }
        }
        else if args.cmd_list {
            let names = try_exit(auth.list(cert_type), args.flag_v || args.flag_verbose);

            for name in names {
                println!("{}", name);
            }
        }
        else if args.cmd_bootstrap && args.cmd_host {
            unimplemented!();
        }
    }
}

fn try_exit<T, E>(r: StdResult<T, E>, verbose: bool) -> T
    where E: Into<Error> + Debug + Display {
    if let Err(e) = r {
        println!("{}", e);

        if verbose {
            println!("{:?}", e);
        }

        exit(1);
    }

    r.unwrap()
}
<|endoftext|>


<commit_before>use std::f32::consts;
use std::mem;

#[test]
fn it_works() {
}

 fn main() {
    // FIXME these are a function input
    let input_lon: f32 = 0.1275;
    let input_lat: f32 = 51.5072;

    let pi: f32 = consts::PI;
    //Convert input to degrees
    let lat_1: f32 = input_lat * pi / 180.;
    let lon_1: f32 = input_lon * pi / 180.;
    // The GSR80 semi-major and semi-minor axes used for WGS84 (m)
    let a_1: f32 = 6378137.;
    let b_1: f32 = 6356752.3141;
    // The eccentricity (squared) of the GRS80 ellipsoid
    let e2_1: f32 = 1. as f32 - (b_1.powf(2.)) / (a_1.powf(2.));
    // Transverse radius of curvature
    let nu_1: f32 = a_1 / (1. as f32 - e2_1 * lat_1.sin().powf(2.)).sqrt();
    // Third spherical coordinate is 0, in this case
    let H: f32 = 0.;
    let x_1: f32 = (nu_1 + H) * lat_1.cos() * lon_1.cos();
    let y_1: f32 = (nu_1 + H) * lat_1.cos() * lon_1.sin();
    let z_1: f32 = ((1. as f32 - e2_1) * nu_1 + H) * lat_1.sin();

    // Perform Helmert transform (to go between Airy 1830 (_1) and GRS80 (_2))
    let small: f32 = 10.;
    let cst: f32 = 20.4894;
    let s: f32 =  cst * small.powf(-6.);
    // The translations along x, y, z axes respectively
    let tx: f32 = -446.448;
    let ty: f32 = 125.157;
    let tz: f32 = -542.060;
    // The rotations along x, y, z respectively, in seconds
    let rxs: f32 = 0.1502;
    let rys: f32 = -0.2470;
    let rzs: f32 = -0.8421;
    // In radians
    let rx: f32 = rxs * pi / (180 as f32 * 3600 as f32);
    let ry: f32 = rys * pi / (180 as f32 * 3600 as f32);
    let rz: f32 = rzs * pi / (180 as f32 * 3600 as f32);
    // panic begins on line 46
    let x_2: f32 = tx + 1 as f32 + s * x_1 + -rz * y_1 + ry * z_1;
    let y_2: f32 = ty + rz * x_1 + 1 as f32+ s * y_1 + -rx * z_1;
    let z_2: f32 = tz + -ry * x_1 + rx * y_1 + 1 as f32 + s * z_1;

    // The GSR80 semi-major and semi-minor axes used for WGS84 (m)
    let a: f32 = 6377563.396;
    let b: f32 = 6356256.909;
    // The eccentricity of the Airy 1830 ellipsoid
    let e2: f32 = 1 as f32 - b.powf(2.) / a.powf(2.);
    let p: f32 = (x_2.powf(2.) + y_2.powf(2.)).sqrt();
    // Initial value
    let mut lat: f32 = z_2.atan2((p * (1 as f32 - e2)));
    let mut latold: f32 = 2 as f32 * pi;
    // this is cheating, but not sure how else to initialise nu
    let mut nu: f32 = 1.;
    // Latitude is obtained by iterative procedure
    while (lat - latold).abs() > small.powf(-16.) {
        // (lat, latold) = (latold, lat);
        mem::swap(&mut lat, &mut latold);
        nu = a / (1 as f32 - e2 * latold.sin().powf(2.)).sqrt();
        lat = (z_2 + e2 * nu * latold.sin()).atan2(p);
    };
    let lon: f32 = y_2.atan2(x_2);
    let H: f32 = p / lat.cos() - nu;
    // Scale factor on the central meridian
    let F0: f32 = 0.9996012717;
    // Latitude of true origin (radians)
    let lat0: f32 = 49 as f32 * pi / 180 as f32;
    // Longtitude of true origin and central meridian (radians)
    let lon0: f32 = -2 as f32 * pi / 180 as f32;
    // Northing & easting of true origin (m)
    let N0: f32 = -100000.;
    let E0: f32 = 400000.;
    let n: f32 = (a - b) / (a + b);
    // Meridional radius of curvature
    let rho: f32 = a * F0 * (1. as f32 - e2) * (1. as f32 - e2 * lat.sin().powf(2.)).powf(-1.5);
    let eta2: f32 = nu * F0 / rho - 1 as f32;

    let M1: f32 = (1 as f32 + n + (5 as f32 /4 as f32) * n.powf(2.) + (5 as f32 / 4 as f32) * n.powf(3.)) * (lat - lat0);
    let M2: f32 = (3 as f32* n + 3 as f32 * n.powf(2.) + (21 as f32 / 8 as f32) * n.powf(3.)) * (lat - lat0).sin() * (lat + lat0).cos();
    let M3: f32 = ((15 as f32 / 8 as f32) * n.powf(2.) + (15 as f32/ 8 as f32) * n.powf(3.)) * (2 as f32 * (lat-lat0)).sin() * (2 as f32 * (lat + lat0)).cos();
    let M4: f32 = (35 as f32 / 24 as f32) * n.powf(3 as f32) * (3 as f32* (lat - lat0)).sin() * (3 as f32 * (lat + lat0)).cos();
    let M: f32 = b * F0 * (M1 - M2 + M3 - M4);

    let I: f32 = M + N0;
    let II: f32 = nu * F0 * lat.sin() * lat.cos() / 2.;
    let III: f32 = nu * F0 * lat.sin() * lat.cos().powf(3.) * (5. - lat.tan().powf(2.) + 9. * eta2) / 24.;
    let IIIA: f32 = nu * F0 * lat.sin() * lat.cos().powf(5.) * (61. - 58. * lat.tan().powf(2.) + lat.tan().powf(4.)) / 720.;
    let IV: f32 = nu * F0 * lat.cos();
    let V: f32 = nu * F0 * lat.cos().powf(3.) * (nu / rho - lat.tan().powf(2.)) / 6.;
    let VI: f32 = nu * F0 * lat.cos().powf(5.) * (5. - 18. * lat.tan().powf(2.) + lat.tan().powf(4.) + 14. * eta2 - 58. * eta2 * lat.tan().powf(2.)) / 120.;
    let N: f32 = I + II * (lon - lon0).powf(2.) + III * (lon - lon0).powf(4.) + IIIA * (lon - lon0).powf(6.);
    let E: f32 = E0 + IV * (lon - lon0) + V * (lon - lon0).powf(3.) + VI * (lon - lon0).powf(5.);
    println!("{:?}", (E.to_string(), N.to_string()));
}
<commit_msg>Answers look correct now<commit_after>use std::f32::consts;
use std::mem;

#[test]
fn it_works() {
}

 fn main() {
    // FIXME these are a function input
    // let input_lon: f32 = 0.1275;
    // let input_lat: f32 = 51.5072;

    let input_lat: f32 = 51.44533267;
    let input_lon: f32 = -0.32824866;

    let pi: f32 = consts::PI;
    //Convert input to degrees
    let lat_1: f32 = input_lat * pi / 180.;
    let lon_1: f32 = input_lon * pi / 180.;
    // The GSR80 semi-major and semi-minor axes used for WGS84 (m)
    let a_1: f32 = 6378137.;
    let b_1: f32 = 6356752.3141;
    // The eccentricity (squared) of the GRS80 ellipsoid
    let e2_1: f32 = 1. as f32 - (b_1.powf(2.)) / (a_1.powf(2.));
    // Transverse radius of curvature
    let nu_1: f32 = a_1 / (1. as f32 - e2_1 * lat_1.sin().powf(2.)).sqrt();
    // Third spherical coordinate is 0, in this case
    let H: f32 = 0.;
    let x_1: f32 = (nu_1 + H) * lat_1.cos() * lon_1.cos();
    let y_1: f32 = (nu_1 + H) * lat_1.cos() * lon_1.sin();
    let z_1: f32 = ((1. as f32 - e2_1) * nu_1 + H) * lat_1.sin();

    // Perform Helmert transform (to go between Airy 1830 (_1) and GRS80 (_2))
    let small: f32 = 10.;
    let cst: f32 = 20.4894;
    let s: f32 =  cst * small.powf(-6.);
    // The translations along x, y, z axes respectively
    let tx: f32 = -446.448;
    let ty: f32 = 125.157;
    let tz: f32 = -542.060;
    // The rotations along x, y, z respectively, in seconds
    let rxs: f32 = -0.1502;
    let rys: f32 = -0.2470;
    let rzs: f32 = -0.8421;
    // In radians
    let rx: f32 = rxs * pi / (180. * 3600. as f32);
    let ry: f32 = rys * pi / (180. * 3600. as f32);
    let rz: f32 = rzs * pi / (180. * 3600. as f32);
    // panic begins on line 46
    let x_2: f32 = tx + (1. + s) * x_1 + -rz * y_1 + ry * z_1;
    let y_2: f32 = ty + rz * x_1 + (1. + s) * y_1 + -rx * z_1;
    let z_2: f32 = tz + -ry * x_1 + rx * y_1 + (1. + s) * z_1;

    // The GSR80 semi-major and semi-minor axes used for WGS84 (m)
    let a: f32 = 6377563.396;
    let b: f32 = 6356256.909;
    // The eccentricity of the Airy 1830 ellipsoid
    let e2: f32 = 1 as f32 - b.powf(2.) / a.powf(2.);
    println!("{:?}", (rx, ry, rz));
    println!("{:?}", (x_2, y_2, z_2));
    let p: f32 = (x_2.powf(2.) + y_2.powf(2.)).sqrt();
    // Initial value
    let mut lat: f32 = z_2.atan2((p * (1 as f32 - e2)));
    let mut latold: f32 = 2 as f32 * pi;
    // this is cheating, but not sure how else to initialise nu
    let mut nu: f32 = 1.;
    // Latitude is obtained by iterative procedure
    while (lat - latold).abs() > small.powf(-16.) {
        // (lat, latold) = (latold, lat);
        mem::swap(&mut lat, &mut latold);
        nu = a / (1 as f32 - e2 * latold.sin().powf(2.)).sqrt();
        lat = (z_2 + e2 * nu * latold.sin()).atan2(p);
    };
    let lon: f32 = y_2.atan2(x_2);
    println!("{:?}", (lat, latold, lon));
    let H: f32 = p / lat.cos() - nu;
    // Scale factor on the central meridian
    let F0: f32 = 0.9996012717;
    // Latitude of true origin (radians)
    let lat0: f32 = 49 as f32 * pi / 180 as f32;
    // Longtitude of true origin and central meridian (radians)
    let lon0: f32 = -2 as f32 * pi / 180 as f32;
    // Northing & easting of true origin (m)
    let N0: f32 = -100000.;
    let E0: f32 = 400000.;
    let n: f32 = (a - b) / (a + b);
    // Meridional radius of curvature
    let rho: f32 = a * F0 * (1. as f32 - e2) * (1. as f32 - e2 * lat.sin().powf(2.)).powf(-1.5);
    let eta2: f32 = nu * F0 / rho - 1 as f32;

    let M1: f32 = (1 as f32 + n + (5 as f32 /4 as f32) * n.powf(2.) + (5 as f32 / 4 as f32) * n.powf(3.)) * (lat - lat0);
    let M2: f32 = (3 as f32* n + 3 as f32 * n.powf(2.) + (21 as f32 / 8 as f32) * n.powf(3.)) * (lat - lat0).sin() * (lat + lat0).cos();
    let M3: f32 = ((15 as f32 / 8 as f32) * n.powf(2.) + (15 as f32/ 8 as f32) * n.powf(3.)) * (2 as f32 * (lat-lat0)).sin() * (2 as f32 * (lat + lat0)).cos();
    let M4: f32 = (35 as f32 / 24 as f32) * n.powf(3 as f32) * (3 as f32* (lat - lat0)).sin() * (3 as f32 * (lat + lat0)).cos();
    let M: f32 = b * F0 * (M1 - M2 + M3 - M4);

    let I: f32 = M + N0;
    let II: f32 = nu * F0 * lat.sin() * lat.cos() / 2.;
    let III: f32 = nu * F0 * lat.sin() * lat.cos().powf(3.) * (5. - lat.tan().powf(2.) + 9. * eta2) / 24.;
    let IIIA: f32 = nu * F0 * lat.sin() * lat.cos().powf(5.) * (61. - 58. * lat.tan().powf(2.) + lat.tan().powf(4.)) / 720.;
    let IV: f32 = nu * F0 * lat.cos();
    let V: f32 = nu * F0 * lat.cos().powf(3.) * (nu / rho - lat.tan().powf(2.)) / 6.;
    let VI: f32 = nu * F0 * lat.cos().powf(5.) * (5. - 18. * lat.tan().powf(2.) + lat.tan().powf(4.) + 14. * eta2 - 58. * eta2 * lat.tan().powf(2.)) / 120.;
    let N: f32 = I + II * (lon - lon0).powf(2.) + III * (lon - lon0).powf(4.) + IIIA * (lon - lon0).powf(6.);
    let E: f32 = E0 + IV * (lon - lon0) + V * (lon - lon0).powf(3.) + VI * (lon - lon0).powf(5.);
    println!("{:?}", (N.to_string(), E.to_string()));
}
<|endoftext|>


<commit_before>pub mod miniml_grammar;
pub mod ast;

use ast::{Type, Expr, TopLevelCmd};
type Name = String;

use std::collections::HashMap;
use std::fmt;
use std::io;
use std::io::Write;

/////////  type_check.ml ////////////////

fn check(ctx: &mut HashMap<Name,Type>, t: &Type, e: &Expr) -> Result<(), String> {
    let t_ctx = try!(type_of(ctx, e));
    if *t == t_ctx {
        Ok(())
    } else {
        Err(format!("{} has type of {} but is used as if it has type {}.", e, t, t_ctx))
    }
}

fn type_of<'a, 'b>(ctx: &'a mut HashMap<Name,Type>, e: &'b Expr) -> Result<Type, String> {
    match *e {
        Expr::Var(ref name) => {
            if let Some(t) = ctx.get(name) {
                Ok(t.clone())
            } else {
                Err(format!("Variable name {} not found.", name))
            }
        },
        Expr::Int(_) => Ok(Type::Int),
        Expr::Bool(_) => Ok(Type::Bool),
        Expr::Times(ref e1, ref e2) => {try!(check(ctx, &Type::Int, e1)); try!(check(ctx, &Type::Int, e2)); Ok(Type::Int) },
        Expr::Plus(ref e1, ref e2) => {try!(check(ctx, &Type::Int, e1)); try!(check(ctx, &Type::Int, e2)); Ok(Type::Int) },
        Expr::Minus(ref e1, ref e2) => {try!(check(ctx, &Type::Int, e1)); try!(check(ctx, &Type::Int, e2)); Ok(Type::Int) },
        Expr::Equal(ref e1, ref e2) => {try!(check(ctx, &Type::Int, e1)); try!(check(ctx, &Type::Int, e2)); Ok(Type::Bool) },
        Expr::Less(ref e1, ref e2) => {try!(check(ctx, &Type::Int, e1)); try!(check(ctx, &Type::Int, e2)); Ok(Type::Bool) },
        Expr::If(ref e1, ref e2, ref e3) => {
            try!(check(ctx, &Type::Bool, e1));
            let t2 = try!(type_of(ctx, e2));
            try!(check(ctx, &t2, e3));
            Ok(t2)
        },
        Expr::Fn(ref f, ref x, ref ty1, ref ty2, ref e) => {
            ctx.insert((*f).clone(), Type::Arrow(Box::new((*ty1).clone()), Box::new((*ty2).clone())));
            ctx.insert((*x).clone(), (*ty1).clone());
            try!(check(ctx, ty2, e));
            Ok(Type::Arrow(Box::new((*ty1).clone()), Box::new((*ty2).clone())))
        },
        Expr::Apply(ref e1, ref e2) => {
            let ty = try!(type_of(ctx, e1));
            match ty {
                Type::Arrow(ref ty1, ref ty2) => {
                    try!(check(ctx, ty1, e2));
                    Ok((**ty2).clone())
                },
                wrong_type => Err(format!("{} is used as a function but its type is {}", e1, wrong_type))
            }
        }
    }
}

///////// end type check ////////////

///////// machine.ml ///////////////

// type Name = String above
type Frame = Vec<Instr>;
type Environ = HashMap<Name, Mvalue>;

#[derive(Clone, Debug)]
enum Mvalue {
    Int(i64),
    Bool(bool),
    Closure(Name, Frame, Environ)
}

impl fmt::Display for Mvalue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Mvalue::Int(i) => write!(f, "{}", i),
            Mvalue::Bool(b) => write!(f, "{}", b),
            Mvalue::Closure(_, _, _) => write!(f, "<fun>")
        }
    }
}

#[derive(Clone, Debug)]
enum Instr {
    Mult,
    Add,
    Sub,
    Equal,
    Less,
    Var(Name),
    Int(i64),
    Bool(bool),
    Closure(Name, Name, Frame),
    Branch(Frame, Frame),
    Call,
    PopEnv,
}

fn lookup(x: &Name, envs: &mut Vec<Environ>) -> Result<Mvalue, String> {
    if let Some(env) = envs.get_mut(0) {
        if let Some(v) = env.get(x) {
            Ok((*v).clone())
        } else {
            Err(format!("Variable {} not found in environment!", x))
        }
    } else {
        return Err("Can't look up. No environment in stack".to_string())
    }
}

fn pop_bool(s: &mut Vec<Mvalue>) -> Result<bool, String> {
    if let Some(val) = s.pop() {
        match val {
            Mvalue::Bool(b) => Ok(b),
            _ => Err(format!("Bool expected, but got {}", val))
        }
    } else {
        Err("No values on stack.".to_string())
    }
}

fn pop_app(s: &mut Vec<Mvalue>) -> Result<(Name, Frame, Environ, Mvalue), String> {
    if let (Some(v1), Some(v2)) = (s.pop(), s.pop()) {
        match v2 {
            Mvalue::Closure(n, f, e) => Ok((n, f, e, v1)),
            _ => Err(format!("Value and closure expected, got {} and {}", v1, v2))
        }
    } else {
        Err("Two elements expected on stack, but were not there.".to_string())
    }
}

fn mult(s: &mut Vec<Mvalue>) -> Result<(), String> {
    if let (Some(Mvalue::Int(i1)), Some(Mvalue::Int(i2))) = (s.pop(), s.pop()) {
        s.push(Mvalue::Int(i1*i2));
        Ok(())
    } else {
        Err("To ints expected for mult, but not on stack".to_string())
    }
}

fn add(s: &mut Vec<Mvalue>) -> Result<(), String> {
    if let (Some(Mvalue::Int(i1)), Some(Mvalue::Int(i2))) = (s.pop(), s.pop()) {
        s.push(Mvalue::Int(i1+i2));
        Ok(())
    } else {
        Err("To ints expected for add, but not on stack".to_string())
    }
}

fn sub(s: &mut Vec<Mvalue>) -> Result<(), String> {
    if let (Some(Mvalue::Int(i1)), Some(Mvalue::Int(i2))) = (s.pop(), s.pop()) {
        s.push(Mvalue::Int(i1-i2));
        Ok(())
    } else {
        Err("To ints expected for sub, but not on stack".to_string())
    }
}

fn equal(s: &mut Vec<Mvalue>) -> Result<(), String> {
    if let (Some(Mvalue::Int(i1)), Some(Mvalue::Int(i2))) = (s.pop(), s.pop()) {
        s.push(Mvalue::Bool(i1 == i2));
        Ok(())
    } else {
        Err("To ints expected for equal, but not on stack".to_string())
    }
}

fn less(s: &mut Vec<Mvalue>) -> Result<(), String> {
    if let (Some(Mvalue::Int(i1)), Some(Mvalue::Int(i2))) = (s.pop(), s.pop()) {
        s.push(Mvalue::Bool(i1 < i2));
        Ok(())
    } else {
        Err("To ints expected for less, but not on stack".to_string())
    }
}

fn exec(instr: Instr, frms: &mut Vec<Frame>, stack: &mut Vec<Mvalue>, envs: &mut Vec<Environ>) -> Result<(), String> {
    match instr {
        // arithemetic
        Instr::Mult => { mult(stack) }
        Instr::Add => { add(stack) }
        Instr::Sub => { sub(stack) }
        Instr::Equal => { equal(stack) }
        Instr::Less => { less(stack) }

        // pushing values onto stack
        Instr::Var(name) => {
            let val = try!(lookup(&name, envs));
            Ok(stack.push(val))
        }
        Instr::Int(i) => { Ok(stack.push(Mvalue::Int(i))) }
        Instr::Bool(b) => { Ok(stack.push(Mvalue::Bool(b))) }
        Instr::Closure(f, x, frm) => {
            let env = try!((*envs).first().ok_or("No environments in closure.".to_string()));
            let mut c = Mvalue::Closure(x, frm, (*env).clone());
            let c2 = c.clone();

            match c {
                Mvalue::Closure(_, _, ref mut e) => {
                    e.insert(f, c2);
                },
                _ => unreachable!()
            }
            Ok(stack.push(c))
        }
        Instr::Branch(f1, f2) => {
            let b = try!(pop_bool(stack));

            if b {
                Ok(frms.push(f1))
            } else {
                Ok(frms.push(f2))
            }
        }
        Instr::Call => {
            let (x, f, mut e, v) = try!(pop_app(stack));
            (*frms).push(f);
            e.insert(x, v);
            (*envs).push(e);
            Ok(())
        }
        Instr::PopEnv => {
            if let Some(_) = (*envs).pop() {
                Ok(())
            } else {
                Err("No environment to pop.".to_string())
            }
        }
    }
}

fn run(frm: Frame, env: &mut Environ) -> Result<Mvalue, String> {
    let mut frms: Vec<Frame> = vec![frm];
    let mut stack: Vec<Mvalue> = vec![];
    let mut envs: Vec<Environ> = vec![env.clone()];

    loop {
        if frms.len() == 0 && stack.len() == 1 {
            return Ok(stack.pop().unwrap())
        } else if frms.len() >= 1 && frms.first().unwrap().len() >=1 {
            let mut frm = frms.pop().unwrap();
            let i = try!(frm.pop().ok_or("No instructions in this frame."));
            frms.push(frm);
            try!(exec(i, &mut frms, &mut stack, &mut envs));
        } else if frms.len() >= 1 && frms.first().unwrap().len() == 0 {
            frms.pop();
        } else {
            return Err("Illegal end of program.".to_string())
        }
    }
}

/////////////// end machine /////////////////////

///////////// compile.ml ////////////////////

// MiniML compiler Expr -> Instr
fn compile(expr: Expr) -> Vec<Instr> {
    match expr {
        Expr::Var(x) => vec![Instr::Var(x)],
        Expr::Int(k) => vec![Instr::Int(k)],
        Expr::Bool(b) => vec![Instr::Bool(b)],
        Expr::Times(e1, e2) => {
            let mut instrs = compile(*e1);
            instrs.extend(compile(*e2));
            instrs.extend(vec![Instr::Mult]);
            instrs
        }
        Expr::Plus(e1, e2) => {
            let mut instrs = compile(*e1);
            instrs.extend(compile(*e2));
            instrs.extend(vec![Instr::Add]);
            instrs
        }
        Expr::Minus(e1, e2) => {
            let mut instrs = compile(*e1);
            instrs.extend(compile(*e2));
            instrs.extend(vec![Instr::Sub]);
            instrs
        }
        Expr::Equal(e1, e2) => {
            let mut instrs = compile(*e1);
            instrs.extend(compile(*e2));
            instrs.extend(vec![Instr::Equal]);
            instrs
        }
        Expr::Less(e1, e2) => {
            let mut instrs = compile(*e1);
            instrs.extend(compile(*e2));
            instrs.extend(vec![Instr::Less]);
            instrs
        }
        Expr::If(e1, e2, e3) => {
            let mut cond_instrs = compile(*e1);
            let true_instrs = compile(*e2);
            let false_instrs = compile(*e3);
            cond_instrs.extend(vec![Instr::Branch(true_instrs, false_instrs)]);
            cond_instrs
        }
        Expr::Fn(f, x, _, _, e) => {
            let mut func_body = compile(*e);
            func_body.extend(vec![Instr::PopEnv]);
            vec![Instr::Closure((*f).to_string(), (*x).to_string(), func_body)]
        }

        Expr::Apply(e1, e2) => {
            let mut instrs = compile(*e1);
            instrs.extend(compile(*e2));
            instrs.extend(vec![Instr::Call]);
            instrs
        }
    }
}
////////////// end compile /////////////

////////// miniml.ml //////////////

//[exec_cmd (ctx, env) cmd] executes the toplevel command [cmd] and
// returns the new context-environment pair and a string representing the
// result of evaluation.
fn exec_cmd(ctx: &mut HashMap<Name, Type>, env: &mut Environ, cmd: TopLevelCmd) -> Result<String, String> {
    match cmd {
        TopLevelCmd::Expr(e) => {
            let ty = try!(type_of(ctx, &e));
            let frm = compile(e);
            let v = try!(run(frm, env));
            Ok(format!("- : {} = {}", ty, v))
        }
        TopLevelCmd::Def(x, e) => {
            let ty = try!(type_of(ctx, &e));
            let frm = compile(e);
            let v = try!(run(frm, env));
            ctx.insert(x.clone(), ty.clone());
            Ok(format!("{} : {} = {}", x, ty, v))
        }
    }
}

fn exec_cmds(ctx: &mut HashMap<Name, Type>, env: &mut Environ, cmds: Vec<TopLevelCmd>) -> Result<String, String> {
    let mut output: String = String::new();
    for cmd in cmds.into_iter() {
        let o = try!(exec_cmd(ctx, env, cmd));
        output = output + "\n";
        output = output + &o;
    }
    Ok(output)
}

fn shell(ctx: &mut HashMap<Name, Type>, env: &mut Environ) {
    println!("Welcome to MiniML.");
    loop {
        print!("MiniML> ");
        if let Err(x) = io::stdout().flush() {
            println!("could not flush: {}", x);
        }
        let mut input = String::new();
        io::stdin().read_line(&mut input).ok().expect("Could not read line.");
        if let Ok(cmds) = parse(input) {
            if let Ok(out) = exec_cmds(ctx, env, cmds) {
                println!("{}", out)
            }
        }
    }
}

fn parse(input: String) -> Result<Vec<TopLevelCmd>, &'static str> {
    Ok(vec![TopLevelCmd::Expr(Expr::Int(5))])
}

////////// end miniml ///////////

fn main() {
    let mut ctx: HashMap<Name, Type> = HashMap::new();
    let mut env: Environ = HashMap::new();
    shell(&mut ctx, &mut env);
}

// #[test]
// fn test_parse_type() {
//     println!("{:?}", miniml_grammar::parse_Type("int -> int"));
// }

#[test]
fn calculator1() {
    assert!(miniml_grammar::parse_Term("22").is_ok());
}
<commit_msg>Good news: Fully translated and compiles! Bad news: kinda doesn't work<commit_after>pub mod miniml_grammar;
pub mod ast;

use ast::{Type, Expr, TopLevelCmd};
type Name = String;

use std::collections::HashMap;
use std::fmt;
use std::io;
use std::io::Write;

/////////  type_check.ml ////////////////

fn check(ctx: &mut HashMap<Name,Type>, t: &Type, e: &Expr) -> Result<(), String> {
    let t_ctx = try!(type_of(ctx, e));
    if *t == t_ctx {
        Ok(())
    } else {
        Err(format!("{} has type of {} but is used as if it has type {}.", e, t, t_ctx))
    }
}

fn type_of<'a, 'b>(ctx: &'a mut HashMap<Name,Type>, e: &'b Expr) -> Result<Type, String> {
    match *e {
        Expr::Var(ref name) => {
            if let Some(t) = ctx.get(name) {
                Ok(t.clone())
            } else {
                Err(format!("Variable name {} not found.", name))
            }
        },
        Expr::Int(_) => Ok(Type::Int),
        Expr::Bool(_) => Ok(Type::Bool),
        Expr::Times(ref e1, ref e2) => {try!(check(ctx, &Type::Int, e1)); try!(check(ctx, &Type::Int, e2)); Ok(Type::Int) },
        Expr::Plus(ref e1, ref e2) => {try!(check(ctx, &Type::Int, e1)); try!(check(ctx, &Type::Int, e2)); Ok(Type::Int) },
        Expr::Minus(ref e1, ref e2) => {try!(check(ctx, &Type::Int, e1)); try!(check(ctx, &Type::Int, e2)); Ok(Type::Int) },
        Expr::Equal(ref e1, ref e2) => {try!(check(ctx, &Type::Int, e1)); try!(check(ctx, &Type::Int, e2)); Ok(Type::Bool) },
        Expr::Less(ref e1, ref e2) => {try!(check(ctx, &Type::Int, e1)); try!(check(ctx, &Type::Int, e2)); Ok(Type::Bool) },
        Expr::If(ref e1, ref e2, ref e3) => {
            try!(check(ctx, &Type::Bool, e1));
            let t2 = try!(type_of(ctx, e2));
            try!(check(ctx, &t2, e3));
            Ok(t2)
        },
        Expr::Fn(ref f, ref x, ref ty1, ref ty2, ref e) => {
            ctx.insert((*f).clone(), Type::Arrow(Box::new((*ty1).clone()), Box::new((*ty2).clone())));
            ctx.insert((*x).clone(), (*ty1).clone());
            try!(check(ctx, ty2, e));
            Ok(Type::Arrow(Box::new((*ty1).clone()), Box::new((*ty2).clone())))
        },
        Expr::Apply(ref e1, ref e2) => {
            let ty = try!(type_of(ctx, e1));
            match ty {
                Type::Arrow(ref ty1, ref ty2) => {
                    try!(check(ctx, ty1, e2));
                    Ok((**ty2).clone())
                },
                wrong_type => Err(format!("{} is used as a function but its type is {}", e1, wrong_type))
            }
        }
    }
}

///////// end type check ////////////

///////// machine.ml ///////////////

// type Name = String above
type Frame = Vec<Instr>;
type Environ = HashMap<Name, Mvalue>;

#[derive(Clone, Debug)]
enum Mvalue {
    Int(i64),
    Bool(bool),
    Closure(Name, Frame, Environ)
}

impl fmt::Display for Mvalue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Mvalue::Int(i) => write!(f, "{}", i),
            Mvalue::Bool(b) => write!(f, "{}", b),
            Mvalue::Closure(_, _, _) => write!(f, "<fun>")
        }
    }
}

#[derive(Clone, Debug)]
enum Instr {
    Mult,
    Add,
    Sub,
    Equal,
    Less,
    Var(Name),
    Int(i64),
    Bool(bool),
    Closure(Name, Name, Frame),
    Branch(Frame, Frame),
    Call,
    PopEnv,
}

fn lookup(x: &Name, envs: &mut Vec<Environ>) -> Result<Mvalue, String> {
    if let Some(env) = envs.get_mut(0) {
        if let Some(v) = env.get(x) {
            Ok((*v).clone())
        } else {
            Err(format!("Variable {} not found in environment!", x))
        }
    } else {
        return Err("Can't look up. No environment in stack".to_string())
    }
}

fn pop_bool(s: &mut Vec<Mvalue>) -> Result<bool, String> {
    if let Some(val) = s.pop() {
        match val {
            Mvalue::Bool(b) => Ok(b),
            _ => Err(format!("Bool expected, but got {}", val))
        }
    } else {
        Err("No values on stack.".to_string())
    }
}

fn pop_app(s: &mut Vec<Mvalue>) -> Result<(Name, Frame, Environ, Mvalue), String> {
    if let (Some(v1), Some(v2)) = (s.pop(), s.pop()) {
        match v2 {
            Mvalue::Closure(n, f, e) => Ok((n, f, e, v1)),
            _ => Err(format!("Value and closure expected, got {} and {}", v1, v2))
        }
    } else {
        Err("Two elements expected on stack, but were not there.".to_string())
    }
}

fn mult(s: &mut Vec<Mvalue>) -> Result<(), String> {
    if let (Some(Mvalue::Int(i1)), Some(Mvalue::Int(i2))) = (s.pop(), s.pop()) {
        s.push(Mvalue::Int(i1*i2));
        Ok(())
    } else {
        Err("To ints expected for mult, but not on stack".to_string())
    }
}

fn add(s: &mut Vec<Mvalue>) -> Result<(), String> {
    if let (Some(Mvalue::Int(i1)), Some(Mvalue::Int(i2))) = (s.pop(), s.pop()) {
        s.push(Mvalue::Int(i1+i2));
        Ok(())
    } else {
        Err("To ints expected for add, but not on stack".to_string())
    }
}

fn sub(s: &mut Vec<Mvalue>) -> Result<(), String> {
    if let (Some(Mvalue::Int(i1)), Some(Mvalue::Int(i2))) = (s.pop(), s.pop()) {
        s.push(Mvalue::Int(i1-i2));
        Ok(())
    } else {
        Err("To ints expected for sub, but not on stack".to_string())
    }
}

fn equal(s: &mut Vec<Mvalue>) -> Result<(), String> {
    if let (Some(Mvalue::Int(i1)), Some(Mvalue::Int(i2))) = (s.pop(), s.pop()) {
        s.push(Mvalue::Bool(i1 == i2));
        Ok(())
    } else {
        Err("To ints expected for equal, but not on stack".to_string())
    }
}

fn less(s: &mut Vec<Mvalue>) -> Result<(), String> {
    if let (Some(Mvalue::Int(i1)), Some(Mvalue::Int(i2))) = (s.pop(), s.pop()) {
        s.push(Mvalue::Bool(i1 < i2));
        Ok(())
    } else {
        Err("To ints expected for less, but not on stack".to_string())
    }
}

fn exec(instr: Instr, frms: &mut Vec<Frame>, stack: &mut Vec<Mvalue>, envs: &mut Vec<Environ>) -> Result<(), String> {
    match instr {
        // arithemetic
        Instr::Mult => { mult(stack) }
        Instr::Add => { add(stack) }
        Instr::Sub => { sub(stack) }
        Instr::Equal => { equal(stack) }
        Instr::Less => { less(stack) }

        // pushing values onto stack
        Instr::Var(name) => {
            let val = try!(lookup(&name, envs));
            Ok(stack.push(val))
        }
        Instr::Int(i) => { Ok(stack.push(Mvalue::Int(i))) }
        Instr::Bool(b) => { Ok(stack.push(Mvalue::Bool(b))) }
        Instr::Closure(f, x, frm) => {
            let env = try!((*envs).first().ok_or("No environments in closure.".to_string()));
            let mut c = Mvalue::Closure(x, frm, (*env).clone());
            let c2 = c.clone();

            match c {
                Mvalue::Closure(_, _, ref mut e) => {
                    e.insert(f, c2);
                },
                _ => unreachable!()
            }
            Ok(stack.push(c))
        }
        Instr::Branch(f1, f2) => {
            let b = try!(pop_bool(stack));

            if b {
                Ok(frms.push(f1))
            } else {
                Ok(frms.push(f2))
            }
        }
        Instr::Call => {
            let (x, f, mut e, v) = try!(pop_app(stack));
            (*frms).push(f);
            e.insert(x, v);
            (*envs).push(e);
            Ok(())
        }
        Instr::PopEnv => {
            if let Some(_) = (*envs).pop() {
                Ok(())
            } else {
                Err("No environment to pop.".to_string())
            }
        }
    }
}

fn run(frm: Frame, env: &mut Environ) -> Result<Mvalue, String> {
    let mut frms: Vec<Frame> = vec![frm];
    let mut stack: Vec<Mvalue> = vec![];
    let mut envs: Vec<Environ> = vec![env.clone()];

    loop {
        if frms.len() == 0 && stack.len() == 1 {
            return Ok(stack.pop().unwrap())
        } else if frms.len() >= 1 && frms.first().unwrap().len() >=1 {
            let mut frm = frms.pop().unwrap();
            let i = try!(frm.pop().ok_or("No instructions in this frame."));
            frms.push(frm);
            try!(exec(i, &mut frms, &mut stack, &mut envs));
        } else if frms.len() >= 1 && frms.first().unwrap().len() == 0 {
            frms.pop();
        } else {
            return Err("Illegal end of program.".to_string())
        }
    }
}

/////////////// end machine /////////////////////

///////////// compile.ml ////////////////////

// MiniML compiler Expr -> Instr
fn compile(expr: Expr) -> Vec<Instr> {
    match expr {
        Expr::Var(x) => vec![Instr::Var(x)],
        Expr::Int(k) => vec![Instr::Int(k)],
        Expr::Bool(b) => vec![Instr::Bool(b)],
        Expr::Times(e1, e2) => {
            let mut instrs = compile(*e1);
            instrs.extend(compile(*e2));
            instrs.extend(vec![Instr::Mult]);
            instrs
        }
        Expr::Plus(e1, e2) => {
            let mut instrs = compile(*e1);
            instrs.extend(compile(*e2));
            instrs.extend(vec![Instr::Add]);
            instrs
        }
        Expr::Minus(e1, e2) => {
            let mut instrs = compile(*e1);
            instrs.extend(compile(*e2));
            instrs.extend(vec![Instr::Sub]);
            instrs
        }
        Expr::Equal(e1, e2) => {
            let mut instrs = compile(*e1);
            instrs.extend(compile(*e2));
            instrs.extend(vec![Instr::Equal]);
            instrs
        }
        Expr::Less(e1, e2) => {
            let mut instrs = compile(*e1);
            instrs.extend(compile(*e2));
            instrs.extend(vec![Instr::Less]);
            instrs
        }
        Expr::If(e1, e2, e3) => {
            let mut cond_instrs = compile(*e1);
            let true_instrs = compile(*e2);
            let false_instrs = compile(*e3);
            cond_instrs.extend(vec![Instr::Branch(true_instrs, false_instrs)]);
            cond_instrs
        }
        Expr::Fn(f, x, _, _, e) => {
            let mut func_body = compile(*e);
            func_body.extend(vec![Instr::PopEnv]);
            vec![Instr::Closure((*f).to_string(), (*x).to_string(), func_body)]
        }

        Expr::Apply(e1, e2) => {
            let mut instrs = compile(*e1);
            instrs.extend(compile(*e2));
            instrs.extend(vec![Instr::Call]);
            instrs
        }
    }
}
////////////// end compile /////////////

////////// miniml.ml //////////////

//[exec_cmd (ctx, env) cmd] executes the toplevel command [cmd] and
// returns the new context-environment pair and a string representing the
// result of evaluation.
fn exec_cmd(ctx: &mut HashMap<Name, Type>, env: &mut Environ, cmd: TopLevelCmd) -> Result<String, String> {
    match cmd {
        TopLevelCmd::Expr(e) => {
            let ty = try!(type_of(ctx, &e));
            let frm = compile(e);
            let v = try!(run(frm, env));
            Ok(format!("- : {} = {}", ty, v))
        }
        TopLevelCmd::Def(x, e) => {
            let ty = try!(type_of(ctx, &e));
            let frm = compile(e);
            let v = try!(run(frm, env));
            ctx.insert(x.clone(), ty.clone());
            Ok(format!("{} : {} = {}", x, ty, v))
        }
    }
}

fn exec_cmds(ctx: &mut HashMap<Name, Type>, env: &mut Environ, cmds: Vec<TopLevelCmd>) -> Result<String, String> {
    let mut output: String = String::new();
    for cmd in cmds.into_iter() {
        let o = try!(exec_cmd(ctx, env, cmd));
        output = output + "\n";
        output = output + &o;
    }
    Ok(output)
}

fn shell(ctx: &mut HashMap<Name, Type>, env: &mut Environ) {
    println!("Welcome to MiniML.");
    loop {
        print!("MiniML> ");
        if let Err(x) = io::stdout().flush() {
            println!("could not flush: {}", x);
        }
        let mut input = String::new();
        io::stdin().read_line(&mut input).ok().expect("Could not read line.");
        if let Ok(cmds) = parse(input) {
            if let Ok(out) = exec_cmds(ctx, env, cmds) {
                println!("{}", out)
            }
        }
    }
}

fn parse(input: String) -> Result<Vec<TopLevelCmd>, ()> {
    match miniml_grammar::parse_Toplevel(&input) {
        Ok(ast) => Ok(ast),
        Err(err) => {
            println!("Parse Error: {:?}", err);
            Err(())
        }
    }
}

////////// end miniml ///////////

fn main() {
    let mut ctx: HashMap<Name, Type> = HashMap::new();
    let mut env: Environ = HashMap::new();
    shell(&mut ctx, &mut env);
}

// #[test]
// fn test_parse_type() {
//     println!("{:?}", miniml_grammar::parse_Type("int -> int"));
// }

#[test]
fn calculator1() {
    assert!(miniml_grammar::parse_Term("22").is_ok());
}
<|endoftext|>


<commit_before>extern crate bencode;
extern crate rand;

mod decoder;
mod download;
mod hash;
mod ipc;
mod metainfo;
mod peer_connection;
mod tracker;
mod tracker_response;

use rand::Rng;
use std::{any, convert, env, thread};
use std::sync::{Arc, Mutex};
use download::Download;

const PEER_ID_PREFIX: &'static str = "-RC0001-";

fn main() {
    // parse command-line arguments
    let args: Vec<String> = env::args().collect();
    if args.len() != 2 {
        println!("Usage: rusty_torrent path/to/myfile.torrent")
    }
    let filename = &args[1];

    match run(filename) {
        Ok(_) => {},
        Err(e) => println!("Error: {:?}", e)
    }
}

fn run(filename: &str) -> Result<(), Error> {
    let our_peer_id = generate_peer_id();
    println!("Using peer id: {}", our_peer_id);

    // parse .torrent file
    let metainfo = try!(metainfo::parse(filename));

    // connect to tracker and download list of peers
    let peers = try!(tracker::get_peers(&our_peer_id, &metainfo));
    println!("Found {} peers", peers.len());

    // create the download metadata object and stuff it inside a reference-counted mutex
    let download = try!(Download::new(our_peer_id, metainfo));
    let download_mutex = Arc::new(Mutex::new(download));

    // spawn threads to connect to peers and start the download
    let peer_threads: Vec<thread::JoinHandle<()>> = peers.into_iter().map(|peer| {
        let mutex = download_mutex.clone();
        thread::spawn(move || {
            match peer_connection::connect(&peer, mutex) {
                Ok(_) => println!("Peer done"),
                Err(e) => println!("Error: {:?}", e)
            }
        })
    }).collect();

    // wait for peers to complete
    for thr in peer_threads {
        try!(thr.join());
    }

    Ok(())
}

fn generate_peer_id() -> String {
    let mut rng = rand::thread_rng();
    let rand_chars: String = rng.gen_ascii_chars().take(20 - PEER_ID_PREFIX.len()).collect();
    format!("{}{}", PEER_ID_PREFIX, rand_chars)
}

#[derive(Debug)]
pub enum Error {
    DecoderError(decoder::Error),
    DownloadError(download::Error),
    TrackerError(tracker::Error),
    Any(Box<any::Any + Send>),
}

impl convert::From<decoder::Error> for Error {
    fn from(err: decoder::Error) -> Error {
        Error::DecoderError(err)
    }
}

impl convert::From<download::Error> for Error {
    fn from(err: download::Error) -> Error {
        Error::DownloadError(err)
    }
}

impl convert::From<tracker::Error> for Error {
    fn from(err: tracker::Error) -> Error {
        Error::TrackerError(err)
    }
}

impl convert::From<Box<any::Any + Send>> for Error {
    fn from(err: Box<any::Any + Send>) -> Error {
        Error::Any(err)
    }
}<commit_msg>Changed to a println and error message the case in which no input file was not input as argument.<commit_after>extern crate bencode;
extern crate rand;

mod decoder;
mod download;
mod hash;
mod ipc;
mod metainfo;
mod peer_connection;
mod tracker;
mod tracker_response;

use rand::Rng;
use std::{any, convert, env, process, thread};
use std::sync::{Arc, Mutex};
use download::Download;

const PEER_ID_PREFIX: &'static str = "-RC0001-";

fn main() {
    // parse command-line arguments
    let args: Vec<String> = env::args().collect();
    if args.len() != 2 {
        println!("Usage: rusty_torrent path/to/myfile.torrent");
        process::exit(1)
    }
    let filename = &args[1];

    match run(filename) {
        Ok(_) => {},
        Err(e) => println!("Error: {:?}", e)
    }
}

fn run(filename: &str) -> Result<(), Error> {
    let our_peer_id = generate_peer_id();
    println!("Using peer id: {}", our_peer_id);

    // parse .torrent file
    let metainfo = try!(metainfo::parse(filename));

    // connect to tracker and download list of peers
    let peers = try!(tracker::get_peers(&our_peer_id, &metainfo));
    println!("Found {} peers", peers.len());

    // create the download metadata object and stuff it inside a reference-counted mutex
    let download = try!(Download::new(our_peer_id, metainfo));
    let download_mutex = Arc::new(Mutex::new(download));

    // spawn threads to connect to peers and start the download
    let peer_threads: Vec<thread::JoinHandle<()>> = peers.into_iter().map(|peer| {
        let mutex = download_mutex.clone();
        thread::spawn(move || {
            match peer_connection::connect(&peer, mutex) {
                Ok(_) => println!("Peer done"),
                Err(e) => println!("Error: {:?}", e)
            }
        })
    }).collect();

    // wait for peers to complete
    for thr in peer_threads {
        try!(thr.join());
    }

    Ok(())
}

fn generate_peer_id() -> String {
    let mut rng = rand::thread_rng();
    let rand_chars: String = rng.gen_ascii_chars().take(20 - PEER_ID_PREFIX.len()).collect();
    format!("{}{}", PEER_ID_PREFIX, rand_chars)
}

#[derive(Debug)]
pub enum Error {
    DecoderError(decoder::Error),
    DownloadError(download::Error),
    TrackerError(tracker::Error),
    Any(Box<any::Any + Send>),
}

impl convert::From<decoder::Error> for Error {
    fn from(err: decoder::Error) -> Error {
        Error::DecoderError(err)
    }
}

impl convert::From<download::Error> for Error {
    fn from(err: download::Error) -> Error {
        Error::DownloadError(err)
    }
}

impl convert::From<tracker::Error> for Error {
    fn from(err: tracker::Error) -> Error {
        Error::TrackerError(err)
    }
}

impl convert::From<Box<any::Any + Send>> for Error {
    fn from(err: Box<any::Any + Send>) -> Error {
        Error::Any(err)
    }
}<|endoftext|>