<commit_before>#![cfg_attr(test, deny(warnings))]
#![recursion_limit="128"]

// Currently, Cargo does not use clippy for its source code.
// But if someone runs it they should know that
// @alexcrichton disagree with clippy on some style things
#![cfg_attr(feature = "cargo-clippy", allow(explicit_iter_loop))]

#[macro_use] extern crate failure;
#[macro_use] extern crate log;
#[macro_use] extern crate scoped_tls;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate serde_json;
extern crate atty;
extern crate crates_io as registry;
extern crate crossbeam;
extern crate curl;
extern crate docopt;
extern crate filetime;
extern crate flate2;
extern crate fs2;
extern crate git2;
extern crate glob;
extern crate hex;
extern crate home;
extern crate ignore;
extern crate jobserver;
extern crate lazycell;
#[macro_use] extern crate lazy_static;
extern crate libc;
extern crate libgit2_sys;
extern crate num_cpus;
extern crate same_file;
extern crate semver;
extern crate serde;
extern crate serde_ignored;
extern crate shell_escape;
extern crate tar;
extern crate tempdir;
extern crate termcolor;
extern crate toml;
extern crate url;
#[cfg(target_os = "macos")]
extern crate core_foundation;

use std::fmt;

use serde::de::DeserializeOwned;
use serde::ser;
use docopt::Docopt;
use failure::Error;

use core::Shell;
use core::shell::Verbosity::Verbose;

pub use util::{CargoError, CargoResult, CliError, CliResult, Config};
pub use util::errors::Internal;

pub const CARGO_ENV: &str = "CARGO";

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

pub struct CommitInfo {
    pub short_commit_hash: String,
    pub commit_hash: String,
    pub commit_date: String,
}

pub struct CfgInfo {
    // Information about the git repository we may have been built from.
    pub commit_info: Option<CommitInfo>,
    // The release channel we were built for.
    pub release_channel: String,
}

pub struct VersionInfo {
    pub major: u8,
    pub minor: u8,
    pub patch: u8,
    pub pre_release: Option<String>,
    // Information that's only available when we were built with
    // configure/make, rather than cargo itself.
    pub cfg_info: Option<CfgInfo>,
}

impl fmt::Display for VersionInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "cargo {}.{}.{}",
               self.major, self.minor, self.patch)?;
        if let Some(channel) = self.cfg_info.as_ref().map(|ci| &ci.release_channel) {
            if channel != "stable" {
                write!(f, "-{}", channel)?;
                let empty = String::from("");
                write!(f, "{}", self.pre_release.as_ref().unwrap_or(&empty))?;
            }
        };

        if let Some(ref cfg) = self.cfg_info {
            if let Some(ref ci) = cfg.commit_info {
                write!(f, " ({} {})",
                       ci.short_commit_hash, ci.commit_date)?;
            }
        };
        Ok(())
    }
}

pub fn call_main_without_stdin<Flags: DeserializeOwned>(
            exec: fn(Flags, &mut Config) -> CliResult,
            config: &mut Config,
            usage: &str,
            args: &[String],
            options_first: bool) -> CliResult
{
    let docopt = Docopt::new(usage).unwrap()
        .options_first(options_first)
        .argv(args.iter().map(|s| &s[..]))
        .help(true);

    let flags = docopt.deserialize().map_err(|e| {
        let code = if e.fatal() {1} else {0};
        CliError::new(e.into(), code)
    })?;

    exec(flags, config)
}

pub fn print_json<T: ser::Serialize>(obj: &T) {
    let encoded = serde_json::to_string(&obj).unwrap();
    println!("{}", encoded);
}

pub fn exit_with_error(err: CliError, shell: &mut Shell) -> ! {
    debug!("exit_with_error; err={:?}", err);

    let CliError { error, exit_code, unknown } = err;
    // exit_code == 0 is non-fatal error, e.g. docopt version info
    let fatal = exit_code != 0;

    let hide = unknown && shell.verbosity() != Verbose;

    if let Some(error) = error {
        if hide {
            drop(shell.error("An unknown error occurred"))
        } else if fatal {
            drop(shell.error(&error))
        } else {
            println!("{}", error);
        }

        if !handle_cause(&error, shell) || hide {
            drop(writeln!(shell.err(), "\nTo learn more, run the command again \
                                        with --verbose."));
        }
    }

    std::process::exit(exit_code)
}

pub fn handle_error(err: CargoError, shell: &mut Shell) {
    debug!("handle_error; err={:?}", &err);

    let _ignored_result = shell.error(&err);
    handle_cause(&err, shell);
}

fn handle_cause(cargo_err: &Error, shell: &mut Shell) -> bool {
    fn print(error: String, shell: &mut Shell) {
        drop(writeln!(shell.err(), "\nCaused by:"));
        drop(writeln!(shell.err(), "  {}", error));
    }

    let verbose = shell.verbosity();

    if verbose == Verbose {
        // The first error has already been printed to the shell
        // Print all remaining errors
        for err in cargo_err.causes().skip(1) {
            print(err.to_string(), shell);
        }
    } else {
        // The first error has already been printed to the shell
        // Print remaining errors until one marked as Internal appears
        for err in cargo_err.causes().skip(1) {
            if err.downcast_ref::<Internal>().is_some() {
                return false;
            }

            print(err.to_string(), shell);
        }
    }

    true
}

pub fn version() -> VersionInfo {
    macro_rules! option_env_str {
        ($name:expr) => { option_env!($name).map(|s| s.to_string()) }
    }

    // So this is pretty horrible...
    // There are two versions at play here:
    //   - version of cargo-the-binary, which you see when you type `cargo --version`
    //   - version of cargo-the-library, which you download from crates.io for use
    //     in your projects.
    //
    // We want to make the `binary` version the same as the corresponding Rust/rustc release.
    // At the same time, we want to keep the library version at `0.x`, because Cargo as
    // a library is (and probably will always be) unstable.
    //
    // Historically, Cargo used the same version number for both the binary and the library.
    // Specifically, rustc 1.x.z was paired with cargo 0.x+1.w.
    // We continue to use this scheme for the library, but transform it to 1.x.w for the purposes
    // of `cargo --version`.
    let major = 1;
    let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap() - 1;
    let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u8>().unwrap();

    match option_env!("CFG_RELEASE_CHANNEL") {
        // We have environment variables set up from configure/make.
        Some(_) => {
            let commit_info =
                option_env!("CFG_COMMIT_HASH").map(|s| {
                    CommitInfo {
                        commit_hash: s.to_string(),
                        short_commit_hash: option_env_str!("CFG_SHORT_COMMIT_HASH").unwrap(),
                        commit_date: option_env_str!("CFG_COMMIT_DATE").unwrap(),
                    }
                });
            VersionInfo {
                major,
                minor,
                patch,
                pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
                cfg_info: Some(CfgInfo {
                    release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(),
                    commit_info,
                }),
            }
        },
        // We are being compiled by Cargo itself.
        None => {
            VersionInfo {
                major,
                minor,
                patch,
                pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
                cfg_info: None,
            }
        }
    }
}
<commit_msg>Remove redundant recursion_limit<commit_after>#![cfg_attr(test, deny(warnings))]

// Currently, Cargo does not use clippy for its source code.
// But if someone runs it they should know that
// @alexcrichton disagree with clippy on some style things
#![cfg_attr(feature = "cargo-clippy", allow(explicit_iter_loop))]

#[macro_use] extern crate failure;
#[macro_use] extern crate log;
#[macro_use] extern crate scoped_tls;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate serde_json;
extern crate atty;
extern crate crates_io as registry;
extern crate crossbeam;
extern crate curl;
extern crate docopt;
extern crate filetime;
extern crate flate2;
extern crate fs2;
extern crate git2;
extern crate glob;
extern crate hex;
extern crate home;
extern crate ignore;
extern crate jobserver;
extern crate lazycell;
#[macro_use] extern crate lazy_static;
extern crate libc;
extern crate libgit2_sys;
extern crate num_cpus;
extern crate same_file;
extern crate semver;
extern crate serde;
extern crate serde_ignored;
extern crate shell_escape;
extern crate tar;
extern crate tempdir;
extern crate termcolor;
extern crate toml;
extern crate url;
#[cfg(target_os = "macos")]
extern crate core_foundation;

use std::fmt;

use serde::de::DeserializeOwned;
use serde::ser;
use docopt::Docopt;
use failure::Error;

use core::Shell;
use core::shell::Verbosity::Verbose;

pub use util::{CargoError, CargoResult, CliError, CliResult, Config};
pub use util::errors::Internal;

pub const CARGO_ENV: &str = "CARGO";

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

pub struct CommitInfo {
    pub short_commit_hash: String,
    pub commit_hash: String,
    pub commit_date: String,
}

pub struct CfgInfo {
    // Information about the git repository we may have been built from.
    pub commit_info: Option<CommitInfo>,
    // The release channel we were built for.
    pub release_channel: String,
}

pub struct VersionInfo {
    pub major: u8,
    pub minor: u8,
    pub patch: u8,
    pub pre_release: Option<String>,
    // Information that's only available when we were built with
    // configure/make, rather than cargo itself.
    pub cfg_info: Option<CfgInfo>,
}

impl fmt::Display for VersionInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "cargo {}.{}.{}",
               self.major, self.minor, self.patch)?;
        if let Some(channel) = self.cfg_info.as_ref().map(|ci| &ci.release_channel) {
            if channel != "stable" {
                write!(f, "-{}", channel)?;
                let empty = String::from("");
                write!(f, "{}", self.pre_release.as_ref().unwrap_or(&empty))?;
            }
        };

        if let Some(ref cfg) = self.cfg_info {
            if let Some(ref ci) = cfg.commit_info {
                write!(f, " ({} {})",
                       ci.short_commit_hash, ci.commit_date)?;
            }
        };
        Ok(())
    }
}

pub fn call_main_without_stdin<Flags: DeserializeOwned>(
            exec: fn(Flags, &mut Config) -> CliResult,
            config: &mut Config,
            usage: &str,
            args: &[String],
            options_first: bool) -> CliResult
{
    let docopt = Docopt::new(usage).unwrap()
        .options_first(options_first)
        .argv(args.iter().map(|s| &s[..]))
        .help(true);

    let flags = docopt.deserialize().map_err(|e| {
        let code = if e.fatal() {1} else {0};
        CliError::new(e.into(), code)
    })?;

    exec(flags, config)
}

pub fn print_json<T: ser::Serialize>(obj: &T) {
    let encoded = serde_json::to_string(&obj).unwrap();
    println!("{}", encoded);
}

pub fn exit_with_error(err: CliError, shell: &mut Shell) -> ! {
    debug!("exit_with_error; err={:?}", err);

    let CliError { error, exit_code, unknown } = err;
    // exit_code == 0 is non-fatal error, e.g. docopt version info
    let fatal = exit_code != 0;

    let hide = unknown && shell.verbosity() != Verbose;

    if let Some(error) = error {
        if hide {
            drop(shell.error("An unknown error occurred"))
        } else if fatal {
            drop(shell.error(&error))
        } else {
            println!("{}", error);
        }

        if !handle_cause(&error, shell) || hide {
            drop(writeln!(shell.err(), "\nTo learn more, run the command again \
                                        with --verbose."));
        }
    }

    std::process::exit(exit_code)
}

pub fn handle_error(err: CargoError, shell: &mut Shell) {
    debug!("handle_error; err={:?}", &err);

    let _ignored_result = shell.error(&err);
    handle_cause(&err, shell);
}

fn handle_cause(cargo_err: &Error, shell: &mut Shell) -> bool {
    fn print(error: String, shell: &mut Shell) {
        drop(writeln!(shell.err(), "\nCaused by:"));
        drop(writeln!(shell.err(), "  {}", error));
    }

    let verbose = shell.verbosity();

    if verbose == Verbose {
        // The first error has already been printed to the shell
        // Print all remaining errors
        for err in cargo_err.causes().skip(1) {
            print(err.to_string(), shell);
        }
    } else {
        // The first error has already been printed to the shell
        // Print remaining errors until one marked as Internal appears
        for err in cargo_err.causes().skip(1) {
            if err.downcast_ref::<Internal>().is_some() {
                return false;
            }

            print(err.to_string(), shell);
        }
    }

    true
}

pub fn version() -> VersionInfo {
    macro_rules! option_env_str {
        ($name:expr) => { option_env!($name).map(|s| s.to_string()) }
    }

    // So this is pretty horrible...
    // There are two versions at play here:
    //   - version of cargo-the-binary, which you see when you type `cargo --version`
    //   - version of cargo-the-library, which you download from crates.io for use
    //     in your projects.
    //
    // We want to make the `binary` version the same as the corresponding Rust/rustc release.
    // At the same time, we want to keep the library version at `0.x`, because Cargo as
    // a library is (and probably will always be) unstable.
    //
    // Historically, Cargo used the same version number for both the binary and the library.
    // Specifically, rustc 1.x.z was paired with cargo 0.x+1.w.
    // We continue to use this scheme for the library, but transform it to 1.x.w for the purposes
    // of `cargo --version`.
    let major = 1;
    let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap() - 1;
    let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u8>().unwrap();

    match option_env!("CFG_RELEASE_CHANNEL") {
        // We have environment variables set up from configure/make.
        Some(_) => {
            let commit_info =
                option_env!("CFG_COMMIT_HASH").map(|s| {
                    CommitInfo {
                        commit_hash: s.to_string(),
                        short_commit_hash: option_env_str!("CFG_SHORT_COMMIT_HASH").unwrap(),
                        commit_date: option_env_str!("CFG_COMMIT_DATE").unwrap(),
                    }
                });
            VersionInfo {
                major,
                minor,
                patch,
                pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
                cfg_info: Some(CfgInfo {
                    release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(),
                    commit_info,
                }),
            }
        },
        // We are being compiled by Cargo itself.
        None => {
            VersionInfo {
                major,
                minor,
                patch,
                pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
                cfg_info: None,
            }
        }
    }
}
<|endoftext|>


<commit_before>pub mod leveldb {
  //dead_code only allowed temporary, to avoid noise during
  //construction work
  #![allow(non_camel_case_types,dead_code)]
  use libc::{c_int,c_char,size_t,c_void};

  pub struct leveldb_t;
  pub struct leveldb_cache_t;
  pub struct leveldb_comparator_t;
  pub struct leveldb_env_t;
  pub struct leveldb_filelock_t;
  pub struct leveldb_filterpolicy_t;
  pub struct leveldb_iterator_t;
  pub struct leveldb_logger_t;
  pub struct leveldb_options_t;
  pub struct leveldb_randomfile_t;
  pub struct leveldb_readoptions_t;
  pub struct leveldb_seqfile_t;
  pub struct leveldb_snapshot_t;
  pub struct leveldb_writablefile_t;
  pub struct leveldb_writebatch_t;
  pub struct leveldb_writeoptions_t;

  pub enum Compression {
    No = 0,
    Snappy = 1
  }

  pub type destructor_fn = extern "C" fn(obj: *mut c_void);
  pub type comparator_fn = extern "C" fn(
    state: *mut c_void,
    a: *mut c_char, alen: size_t,
    b: *mut c_char, blen: size_t) -> int;
  pub type name_fn = extern "C" fn(
    state: *mut c_void
  ) -> &'static str;

  #[link(name = "leveldb")]
  extern {
    pub fn leveldb_open(options: *mut leveldb_options_t,
                        name: *const c_char,
                        errptr: &mut *const c_char) -> *mut leveldb_t;
    pub fn leveldb_close(database: *mut leveldb_t);
    pub fn leveldb_put(database: *mut leveldb_t,
                       options: *mut leveldb_writeoptions_t,
                       key: *mut c_char,
                       keylen: size_t,
                       val: *mut c_char,
                       vallen: size_t,
                       errptr: &mut *const c_char);

    pub fn leveldb_delete(database: *mut leveldb_t,
                          options: *mut leveldb_writeoptions_t,
                          key: *mut c_char,
                          keylen: size_t,
                          errptr: &mut *const c_char);

    pub fn leveldb_get(database: *mut leveldb_t,
                       options: *mut leveldb_readoptions_t,
                       key: *mut c_char,
                       keylen: size_t,
                       vallen: *const size_t,
                       errptr: &mut *const c_char) -> *const u8;

    pub fn leveldb_options_create() -> *mut leveldb_options_t;
    pub fn leveldb_options_destroy(options: *mut leveldb_options_t);
    pub fn leveldb_options_set_comparator(cache: *mut leveldb_cache_t,
                                          options: *mut leveldb_comparator_t);
    pub fn leveldb_options_set_filter_policy(options: *mut leveldb_options_t,
                                             filter_policy: *mut leveldb_filterpolicy_t);
    pub fn leveldb_options_set_create_if_missing(options: *mut leveldb_options_t,
                                                 create: c_char);
    pub fn leveldb_options_set_error_if_exists(options: *mut leveldb_options_t,
                                               error: c_char);
    pub fn leveldb_options_set_paranoid_checks(options: *mut leveldb_options_t,
                                               checks: c_char);
    pub fn leveldb_options_set_env(options: *mut leveldb_options_t,
                                   env: *mut leveldb_env_t);
    pub fn leveldb_options_set_info_log(options: *mut leveldb_options_t,
                                        logger: *mut leveldb_logger_t);
    pub fn leveldb_options_set_write_buffer_size(options: *mut leveldb_options_t,
                                                 size: size_t);
    pub fn leveldb_options_set_max_open_files(options: *mut leveldb_options_t,
                                              number: c_int);
    pub fn leveldb_options_set_cache(options: *mut leveldb_options_t,
                                     cache: *mut leveldb_cache_t);
    pub fn leveldb_options_set_block_size(options: *mut leveldb_options_t,
                                          block_size: size_t);
    pub fn leveldb_options_set_block_restart_interval(options: *mut leveldb_options_t,
                                                      interval: c_int);
    pub fn leveldb_options_set_compression(options: *mut leveldb_options_t,
                                           compression_level: Compression);

    pub fn leveldb_writeoptions_create() -> *mut leveldb_writeoptions_t;
    pub fn leveldb_writeoptions_destroy(options: *mut leveldb_writeoptions_t);
    pub fn leveldb_writeoptions_set_sync(options: *mut leveldb_writeoptions_t,
                                         sync: c_char);

    pub fn leveldb_readoptions_create() -> *mut leveldb_readoptions_t;
    pub fn leveldb_readoptions_destroy(options: *mut leveldb_readoptions_t);
    pub fn leveldb_readoptions_set_verify_checksums(options: *mut leveldb_readoptions_t,
                                                    verify_checksums: c_char);
    pub fn leveldb_readoptions_set_fill_cache(options: *mut leveldb_readoptions_t,
                                              fill_cache: c_char);
    pub fn leveldb_readoptions_set_snapshot(options: *mut leveldb_readoptions_t,
                                            snapshot: *mut leveldb_snapshot_t);

    pub fn leveldb_create_iterator(database: *mut leveldb_t,
                                   options: *mut leveldb_readoptions_t) -> *mut leveldb_iterator_t;
    pub fn leveldb_iter_destroy(iterator: *mut leveldb_iterator_t);
    pub fn leveldb_iter_valid(iterator: *mut leveldb_iterator_t) -> c_char;
    pub fn leveldb_iter_seek_to_first(iterator: *mut leveldb_iterator_t);
    pub fn leveldb_iter_seek_to_last(iterator: *mut leveldb_iterator_t);
    pub fn leveldb_iter_seek(iterator: *mut leveldb_iterator_t,
                             key: *mut c_char,
                             keylen: size_t);
    pub fn leveldb_iter_next(iterator: *mut leveldb_iterator_t);
    pub fn leveldb_iter_prev(iterator: *mut leveldb_iterator_t);
    pub fn leveldb_iter_key(iterator: *mut leveldb_iterator_t,
                            keylen: *mut size_t) -> *mut c_char;
    pub fn leveldb_iter_value(iterator: *mut leveldb_iterator_t,
                              vallen: *const size_t) -> *const c_char;
    pub fn leveldb_iter_get_error(iterator: *mut leveldb_iterator_t,
                                  errptr: &mut *const c_char);

    pub fn leveldb_comparator_create(state: *mut c_void,
                                     destructor: destructor_fn,
                                     comparator: comparator_fn,
                                     name: name_fn);
    pub fn leveldb_comparator_destroy(comparator: *mut leveldb_comparator_t);
    pub fn leveldb_free(ptr: *mut c_void);
  }
}
<commit_msg>Link to stdc++ (needed for leveldb)<commit_after>pub mod leveldb {
  //dead_code only allowed temporary, to avoid noise during
  //construction work
  #![allow(non_camel_case_types,dead_code)]
  use libc::{c_int,c_char,size_t,c_void};

  pub struct leveldb_t;
  pub struct leveldb_cache_t;
  pub struct leveldb_comparator_t;
  pub struct leveldb_env_t;
  pub struct leveldb_filelock_t;
  pub struct leveldb_filterpolicy_t;
  pub struct leveldb_iterator_t;
  pub struct leveldb_logger_t;
  pub struct leveldb_options_t;
  pub struct leveldb_randomfile_t;
  pub struct leveldb_readoptions_t;
  pub struct leveldb_seqfile_t;
  pub struct leveldb_snapshot_t;
  pub struct leveldb_writablefile_t;
  pub struct leveldb_writebatch_t;
  pub struct leveldb_writeoptions_t;

  pub enum Compression {
    No = 0,
    Snappy = 1
  }

  pub type destructor_fn = extern "C" fn(obj: *mut c_void);
  pub type comparator_fn = extern "C" fn(
    state: *mut c_void,
    a: *mut c_char, alen: size_t,
    b: *mut c_char, blen: size_t) -> int;
  pub type name_fn = extern "C" fn(
    state: *mut c_void
  ) -> &'static str;

  #[link(name = "leveldb")]
  #[link(name = "stdc++")]
  extern {
    pub fn leveldb_open(options: *mut leveldb_options_t,
                        name: *const c_char,
                        errptr: &mut *const c_char) -> *mut leveldb_t;
    pub fn leveldb_close(database: *mut leveldb_t);
    pub fn leveldb_put(database: *mut leveldb_t,
                       options: *mut leveldb_writeoptions_t,
                       key: *mut c_char,
                       keylen: size_t,
                       val: *mut c_char,
                       vallen: size_t,
                       errptr: &mut *const c_char);

    pub fn leveldb_delete(database: *mut leveldb_t,
                          options: *mut leveldb_writeoptions_t,
                          key: *mut c_char,
                          keylen: size_t,
                          errptr: &mut *const c_char);

    pub fn leveldb_get(database: *mut leveldb_t,
                       options: *mut leveldb_readoptions_t,
                       key: *mut c_char,
                       keylen: size_t,
                       vallen: *const size_t,
                       errptr: &mut *const c_char) -> *const u8;

    pub fn leveldb_options_create() -> *mut leveldb_options_t;
    pub fn leveldb_options_destroy(options: *mut leveldb_options_t);
    pub fn leveldb_options_set_comparator(cache: *mut leveldb_cache_t,
                                          options: *mut leveldb_comparator_t);
    pub fn leveldb_options_set_filter_policy(options: *mut leveldb_options_t,
                                             filter_policy: *mut leveldb_filterpolicy_t);
    pub fn leveldb_options_set_create_if_missing(options: *mut leveldb_options_t,
                                                 create: c_char);
    pub fn leveldb_options_set_error_if_exists(options: *mut leveldb_options_t,
                                               error: c_char);
    pub fn leveldb_options_set_paranoid_checks(options: *mut leveldb_options_t,
                                               checks: c_char);
    pub fn leveldb_options_set_env(options: *mut leveldb_options_t,
                                   env: *mut leveldb_env_t);
    pub fn leveldb_options_set_info_log(options: *mut leveldb_options_t,
                                        logger: *mut leveldb_logger_t);
    pub fn leveldb_options_set_write_buffer_size(options: *mut leveldb_options_t,
                                                 size: size_t);
    pub fn leveldb_options_set_max_open_files(options: *mut leveldb_options_t,
                                              number: c_int);
    pub fn leveldb_options_set_cache(options: *mut leveldb_options_t,
                                     cache: *mut leveldb_cache_t);
    pub fn leveldb_options_set_block_size(options: *mut leveldb_options_t,
                                          block_size: size_t);
    pub fn leveldb_options_set_block_restart_interval(options: *mut leveldb_options_t,
                                                      interval: c_int);
    pub fn leveldb_options_set_compression(options: *mut leveldb_options_t,
                                           compression_level: Compression);

    pub fn leveldb_writeoptions_create() -> *mut leveldb_writeoptions_t;
    pub fn leveldb_writeoptions_destroy(options: *mut leveldb_writeoptions_t);
    pub fn leveldb_writeoptions_set_sync(options: *mut leveldb_writeoptions_t,
                                         sync: c_char);

    pub fn leveldb_readoptions_create() -> *mut leveldb_readoptions_t;
    pub fn leveldb_readoptions_destroy(options: *mut leveldb_readoptions_t);
    pub fn leveldb_readoptions_set_verify_checksums(options: *mut leveldb_readoptions_t,
                                                    verify_checksums: c_char);
    pub fn leveldb_readoptions_set_fill_cache(options: *mut leveldb_readoptions_t,
                                              fill_cache: c_char);
    pub fn leveldb_readoptions_set_snapshot(options: *mut leveldb_readoptions_t,
                                            snapshot: *mut leveldb_snapshot_t);

    pub fn leveldb_create_iterator(database: *mut leveldb_t,
                                   options: *mut leveldb_readoptions_t) -> *mut leveldb_iterator_t;
    pub fn leveldb_iter_destroy(iterator: *mut leveldb_iterator_t);
    pub fn leveldb_iter_valid(iterator: *mut leveldb_iterator_t) -> c_char;
    pub fn leveldb_iter_seek_to_first(iterator: *mut leveldb_iterator_t);
    pub fn leveldb_iter_seek_to_last(iterator: *mut leveldb_iterator_t);
    pub fn leveldb_iter_seek(iterator: *mut leveldb_iterator_t,
                             key: *mut c_char,
                             keylen: size_t);
    pub fn leveldb_iter_next(iterator: *mut leveldb_iterator_t);
    pub fn leveldb_iter_prev(iterator: *mut leveldb_iterator_t);
    pub fn leveldb_iter_key(iterator: *mut leveldb_iterator_t,
                            keylen: *mut size_t) -> *mut c_char;
    pub fn leveldb_iter_value(iterator: *mut leveldb_iterator_t,
                              vallen: *const size_t) -> *const c_char;
    pub fn leveldb_iter_get_error(iterator: *mut leveldb_iterator_t,
                                  errptr: &mut *const c_char);

    pub fn leveldb_comparator_create(state: *mut c_void,
                                     destructor: destructor_fn,
                                     comparator: comparator_fn,
                                     name: name_fn);
    pub fn leveldb_comparator_destroy(comparator: *mut leveldb_comparator_t);
    pub fn leveldb_free(ptr: *mut c_void);
  }
}
<|endoftext|>


<commit_before>#![feature(asm,no_std,lang_items,core)]
#![no_std]
#![crate_name="kernel"]

#![allow(unused_must_use)]

#[macro_use]
extern crate core;

use core::prelude::*;
use core::fmt::Write;

macro_rules! println {
    ($($arg:tt)*) => (unsafe { use ::core::fmt::Write; writeln!(::SP.as_mut().unwrap(), $($arg)*) })
}

mod lang;
mod io;
mod dev;

#[allow(dead_code)]
#[repr(u32)]
#[derive(Debug)]
enum EfiMemoryType {
	EfiReservedMemoryType,
	EfiLoaderCode,
	EfiLoaderData,
	EfiBootServicesCode,
	EfiBootServicesData,
	EfiRuntimeServicesCode,
	EfiRuntimeServicesData,
	EfiConventionalMemory,
	EfiUnusableMemory,
	EfiACPIReclaimMemory,
	EfiACPIMemoryNVS,
	EfiMemoryMappedIO,
	EfiMemoryMappedIOPortSpace,
	EfiPalCode,
	EfiMaxMemoryType,
}

#[repr(C)]
struct EfiMemoryDescriptor {
    type_: EfiMemoryType,
    phys_start: u64,
    virt_start: u64,
    npages: u64,
    attrs: u64,
}

#[repr(C)]
pub struct BootProto {
    mem_map: *const EfiMemoryDescriptor,
    map_size: u64,
    map_ent_size: u64
}

struct BootProtoIter {
    map: *const EfiMemoryDescriptor,
    size: u64,
    ent_size: u64,
    idx: u64,
}

impl Iterator for BootProtoIter {
    type Item = *const EfiMemoryDescriptor;
    fn next(&mut self) -> Option<*const EfiMemoryDescriptor> {
        if self.idx * self.ent_size >= self.size {
            None
        } else {
            let r = Some((self.map as u64 + (self.idx*self.ent_size)) as *const EfiMemoryDescriptor);
            self.idx += 1;
            r
        }
    }
}

static mut SP: Option<dev::serial::SerialPort> = None;

#[no_mangle]
pub fn main(bootproto: *const BootProto) {
    let sp = dev::serial::SerialPort::init(0x3F8);

    unsafe {
        SP = Some(sp);
    }

    println!("KERNEL START:");

    unsafe {
        let bpi = BootProtoIter { map: (*bootproto).mem_map, size: (*bootproto).map_size, ent_size: (*bootproto).map_ent_size, idx: 0};

        for region in bpi {
            println!("{:?} from {:x} -> {:x}", (*region).type_, (*region).phys_start, (*region).phys_start+((*region).npages*4096));
        }
    }

    println!("\n\nReached end of main - HALT");
    loop {
        unsafe {
            asm!("hlt");
        }
    }
}
<commit_msg>kernel: use panic in main<commit_after>#![feature(asm,no_std,lang_items,core)]
#![no_std]
#![crate_name="kernel"]

#![allow(unused_must_use)]

#[macro_use]
extern crate core;

use core::prelude::*;
use core::fmt::Write;

macro_rules! println {
    ($($arg:tt)*) => (unsafe { use ::core::fmt::Write; writeln!(::SP.as_mut().unwrap(), $($arg)*) })
}

mod lang;
mod io;
mod dev;

#[allow(dead_code)]
#[repr(u32)]
#[derive(Debug)]
enum EfiMemoryType {
	EfiReservedMemoryType,
	EfiLoaderCode,
	EfiLoaderData,
	EfiBootServicesCode,
	EfiBootServicesData,
	EfiRuntimeServicesCode,
	EfiRuntimeServicesData,
	EfiConventionalMemory,
	EfiUnusableMemory,
	EfiACPIReclaimMemory,
	EfiACPIMemoryNVS,
	EfiMemoryMappedIO,
	EfiMemoryMappedIOPortSpace,
	EfiPalCode,
	EfiMaxMemoryType,
}

#[repr(C)]
struct EfiMemoryDescriptor {
    type_: EfiMemoryType,
    phys_start: u64,
    virt_start: u64,
    npages: u64,
    attrs: u64,
}

#[repr(C)]
pub struct BootProto {
    mem_map: *const EfiMemoryDescriptor,
    map_size: u64,
    map_ent_size: u64
}

struct BootProtoIter {
    map: *const EfiMemoryDescriptor,
    size: u64,
    ent_size: u64,
    idx: u64,
}

impl Iterator for BootProtoIter {
    type Item = *const EfiMemoryDescriptor;
    fn next(&mut self) -> Option<*const EfiMemoryDescriptor> {
        if self.idx * self.ent_size >= self.size {
            None
        } else {
            let r = Some((self.map as u64 + (self.idx*self.ent_size)) as *const EfiMemoryDescriptor);
            self.idx += 1;
            r
        }
    }
}

static mut SP: Option<dev::serial::SerialPort> = None;

#[no_mangle]
pub fn main(bootproto: *const BootProto) {
    let sp = dev::serial::SerialPort::init(0x3F8);

    unsafe {
        SP = Some(sp);
    }

    println!("KERNEL START:");

    unsafe {
        let bpi = BootProtoIter { map: (*bootproto).mem_map, size: (*bootproto).map_size, ent_size: (*bootproto).map_ent_size, idx: 0};

        for region in bpi {
            println!("{:?} from {:x} -> {:x}", (*region).type_, (*region).phys_start, (*region).phys_start+((*region).npages*4096));
        }
    }

    panic!("End of main reached");
}
<|endoftext|>


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

//! The context within which CSS code is parsed.

use context::QuirksMode;
use cssparser::{Parser, SourceLocation, UnicodeRange};
use error_reporting::{ParseErrorReporter, ContextualParseError};
use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator};
#[cfg(feature = "gecko")]
use style_traits::{PARSING_MODE_DEFAULT, PARSING_MODE_ALLOW_UNITLESS_LENGTH, PARSING_MODE_ALLOW_ALL_NUMERIC_VALUES};
use stylesheets::{CssRuleType, Origin, UrlExtraData, Namespaces};

/// Asserts that all ParsingMode flags have a matching ParsingMode value in gecko.
#[cfg(feature = "gecko")]
#[inline]
pub fn assert_parsing_mode_match() {
    use gecko_bindings::structs;

    macro_rules! check_parsing_modes {
        ( $( $a:ident => $b:ident ),*, ) => {
            if cfg!(debug_assertions) {
                let mut modes = ParsingMode::all();
                $(
                    assert_eq!(structs::$a as usize, $b.bits() as usize, stringify!($b));
                    modes.remove($b);
                )*
                assert_eq!(modes, ParsingMode::empty(), "all ParsingMode bits should have an assertion");
            }
        }
    }

    check_parsing_modes! {
        ParsingMode_Default => PARSING_MODE_DEFAULT,
        ParsingMode_AllowUnitlessLength => PARSING_MODE_ALLOW_UNITLESS_LENGTH,
        ParsingMode_AllowAllNumericValues => PARSING_MODE_ALLOW_ALL_NUMERIC_VALUES,
    }
}

/// The context required to report a parse error.
pub struct ParserErrorContext<'a, R: 'a> {
    /// An error reporter to report syntax errors.
    pub error_reporter: &'a R,
}

/// The data that the parser needs from outside in order to parse a stylesheet.
pub struct ParserContext<'a> {
    /// The `Origin` of the stylesheet, whether it's a user, author or
    /// user-agent stylesheet.
    pub stylesheet_origin: Origin,
    /// The extra data we need for resolving url values.
    pub url_data: &'a UrlExtraData,
    /// The current rule type, if any.
    pub rule_type: Option<CssRuleType>,
    /// The mode to use when parsing.
    pub parsing_mode: ParsingMode,
    /// The quirks mode of this stylesheet.
    pub quirks_mode: QuirksMode,
    /// The currently active namespaces.
    pub namespaces: Option<&'a Namespaces>,
}

impl<'a> ParserContext<'a> {
    /// Create a parser context.
    pub fn new(
        stylesheet_origin: Origin,
        url_data: &'a UrlExtraData,
        rule_type: Option<CssRuleType>,
        parsing_mode: ParsingMode,
        quirks_mode: QuirksMode,
    ) -> ParserContext<'a> {
        ParserContext {
            stylesheet_origin: stylesheet_origin,
            url_data: url_data,
            rule_type: rule_type,
            parsing_mode: parsing_mode,
            quirks_mode: quirks_mode,
            namespaces: None,
        }
    }

    /// Create a parser context for on-the-fly parsing in CSSOM
    pub fn new_for_cssom(
        url_data: &'a UrlExtraData,
        rule_type: Option<CssRuleType>,
        parsing_mode: ParsingMode,
        quirks_mode: QuirksMode
    ) -> ParserContext<'a> {
        Self::new(
            Origin::Author,
            url_data,
            rule_type,
            parsing_mode,
            quirks_mode,
        )
    }

    /// Create a parser context based on a previous context, but with a modified rule type.
    pub fn new_with_rule_type(
        context: &'a ParserContext,
        rule_type: CssRuleType,
        namespaces: &'a Namespaces,
    ) -> ParserContext<'a> {
        ParserContext {
            stylesheet_origin: context.stylesheet_origin,
            url_data: context.url_data,
            rule_type: Some(rule_type),
            parsing_mode: context.parsing_mode,
            quirks_mode: context.quirks_mode,
            namespaces: Some(namespaces),
        }
    }

    /// Get the rule type, which assumes that one is available.
    pub fn rule_type(&self) -> CssRuleType {
        self.rule_type.expect("Rule type expected, but none was found.")
    }

    /// Record a CSS parse error with this context’s error reporting.
    pub fn log_css_error<R>(&self,
                            context: &ParserErrorContext<R>,
                            location: SourceLocation,
                            error: ContextualParseError)
        where R: ParseErrorReporter
    {
        let location = SourceLocation {
            line: location.line,
            column: location.column,
        };
        context.error_reporter.report_error(self.url_data, location, error)
    }

    /// Returns whether this is a chrome stylesheets.
    pub fn in_chrome_stylesheet(&self) -> bool {
        self.url_data.is_chrome()
    }
}

// XXXManishearth Replace all specified value parse impls with impls of this
// trait. This will make it easy to write more generic values in the future.
/// A trait to abstract parsing of a specified value given a `ParserContext` and
/// CSS input.
pub trait Parse : Sized {
    /// Parse a value of this type.
    ///
    /// Returns an error on failure.
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                     -> Result<Self, ParseError<'i>>;
}

impl<T> Parse for Vec<T>
where
    T: Parse + OneOrMoreSeparated,
    <T as OneOrMoreSeparated>::S: Separator,
{
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                     -> Result<Self, ParseError<'i>> {
        <T as OneOrMoreSeparated>::S::parse(input, |i| T::parse(context, i))
    }
}

impl Parse for UnicodeRange {
    fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
                     -> Result<Self, ParseError<'i>> {
        UnicodeRange::parse(input).map_err(|e| e.into())
    }
}
<commit_msg>style: Minimal ParserContext cleanup.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! The context within which CSS code is parsed.

use context::QuirksMode;
use cssparser::{Parser, SourceLocation, UnicodeRange};
use error_reporting::{ParseErrorReporter, ContextualParseError};
use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator};
#[cfg(feature = "gecko")]
use style_traits::{PARSING_MODE_DEFAULT, PARSING_MODE_ALLOW_UNITLESS_LENGTH, PARSING_MODE_ALLOW_ALL_NUMERIC_VALUES};
use stylesheets::{CssRuleType, Origin, UrlExtraData, Namespaces};

/// Asserts that all ParsingMode flags have a matching ParsingMode value in gecko.
#[cfg(feature = "gecko")]
#[inline]
pub fn assert_parsing_mode_match() {
    use gecko_bindings::structs;

    macro_rules! check_parsing_modes {
        ( $( $a:ident => $b:ident ),*, ) => {
            if cfg!(debug_assertions) {
                let mut modes = ParsingMode::all();
                $(
                    assert_eq!(structs::$a as usize, $b.bits() as usize, stringify!($b));
                    modes.remove($b);
                )*
                assert_eq!(modes, ParsingMode::empty(), "all ParsingMode bits should have an assertion");
            }
        }
    }

    check_parsing_modes! {
        ParsingMode_Default => PARSING_MODE_DEFAULT,
        ParsingMode_AllowUnitlessLength => PARSING_MODE_ALLOW_UNITLESS_LENGTH,
        ParsingMode_AllowAllNumericValues => PARSING_MODE_ALLOW_ALL_NUMERIC_VALUES,
    }
}

/// The context required to report a parse error.
pub struct ParserErrorContext<'a, R: 'a> {
    /// An error reporter to report syntax errors.
    pub error_reporter: &'a R,
}

/// The data that the parser needs from outside in order to parse a stylesheet.
pub struct ParserContext<'a> {
    /// The `Origin` of the stylesheet, whether it's a user, author or
    /// user-agent stylesheet.
    pub stylesheet_origin: Origin,
    /// The extra data we need for resolving url values.
    pub url_data: &'a UrlExtraData,
    /// The current rule type, if any.
    pub rule_type: Option<CssRuleType>,
    /// The mode to use when parsing.
    pub parsing_mode: ParsingMode,
    /// The quirks mode of this stylesheet.
    pub quirks_mode: QuirksMode,
    /// The currently active namespaces.
    pub namespaces: Option<&'a Namespaces>,
}

impl<'a> ParserContext<'a> {
    /// Create a parser context.
    pub fn new(
        stylesheet_origin: Origin,
        url_data: &'a UrlExtraData,
        rule_type: Option<CssRuleType>,
        parsing_mode: ParsingMode,
        quirks_mode: QuirksMode,
    ) -> Self {
        ParserContext {
            stylesheet_origin,
            url_data,
            rule_type,
            parsing_mode,
            quirks_mode,
            namespaces: None,
        }
    }

    /// Create a parser context for on-the-fly parsing in CSSOM
    pub fn new_for_cssom(
        url_data: &'a UrlExtraData,
        rule_type: Option<CssRuleType>,
        parsing_mode: ParsingMode,
        quirks_mode: QuirksMode,
    ) -> Self {
        Self::new(
            Origin::Author,
            url_data,
            rule_type,
            parsing_mode,
            quirks_mode,
        )
    }

    /// Create a parser context based on a previous context, but with a modified rule type.
    pub fn new_with_rule_type(
        context: &'a ParserContext,
        rule_type: CssRuleType,
        namespaces: &'a Namespaces,
    ) -> ParserContext<'a> {
        ParserContext {
            stylesheet_origin: context.stylesheet_origin,
            url_data: context.url_data,
            rule_type: Some(rule_type),
            parsing_mode: context.parsing_mode,
            quirks_mode: context.quirks_mode,
            namespaces: Some(namespaces),
        }
    }

    /// Get the rule type, which assumes that one is available.
    pub fn rule_type(&self) -> CssRuleType {
        self.rule_type.expect("Rule type expected, but none was found.")
    }

    /// Record a CSS parse error with this context’s error reporting.
    pub fn log_css_error<R>(
        &self,
        context: &ParserErrorContext<R>,
        location: SourceLocation,
        error: ContextualParseError,
    )
    where
        R: ParseErrorReporter,
    {
        let location = SourceLocation {
            line: location.line,
            column: location.column,
        };
        context.error_reporter.report_error(self.url_data, location, error)
    }

    /// Returns whether this is a chrome stylesheets.
    pub fn in_chrome_stylesheet(&self) -> bool {
        self.url_data.is_chrome()
    }
}

// XXXManishearth Replace all specified value parse impls with impls of this
// trait. This will make it easy to write more generic values in the future.
/// A trait to abstract parsing of a specified value given a `ParserContext` and
/// CSS input.
pub trait Parse : Sized {
    /// Parse a value of this type.
    ///
    /// Returns an error on failure.
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                     -> Result<Self, ParseError<'i>>;
}

impl<T> Parse for Vec<T>
where
    T: Parse + OneOrMoreSeparated,
    <T as OneOrMoreSeparated>::S: Separator,
{
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                     -> Result<Self, ParseError<'i>> {
        <T as OneOrMoreSeparated>::S::parse(input, |i| T::parse(context, i))
    }
}

impl Parse for UnicodeRange {
    fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
                     -> Result<Self, ParseError<'i>> {
        UnicodeRange::parse(input).map_err(|e| e.into())
    }
}
<|endoftext|>


<commit_before>use futures::Future;
use serde_json::json;
use std::io::prelude::*;
use std::io::BufReader;
use std::net::TcpListener;
use std::process::{Child, Command, Stdio};
use std::sync::Arc;
use std::time::{Duration, Instant};
use web3::{
    transports::{EventLoopHandle, Http},
    Transport, Web3,
};

/// How long we will wait for ganache to indicate that it is ready.
const GANACHE_STARTUP_TIMEOUT_MILLIS: u64 = 10_000;

/// Provides a dedicated `ganachi-cli` instance with a connected `Web3` instance.
///
/// Requires that `ganachi-cli` is installed and available on `PATH`.
pub struct GanacheInstance {
    pub port: u16,
    child: Child,
    _event_loop: Arc<EventLoopHandle>,
    pub web3: Web3<Http>,
}

impl GanacheInstance {
    /// Start a new `ganache-cli` process, waiting until it indicates that it is ready to accept
    /// RPC connections.
    pub fn new() -> Result<Self, String> {
        let port = unused_port()?;

        let mut child = Command::new("ganache-cli")
            .stdout(Stdio::piped())
            .arg("--defaultBalanceEther")
            .arg("1000000000")
            .arg("--gasLimit")
            .arg("1000000000")
            .arg("--accounts")
            .arg("10")
            .arg("--port")
            .arg(format!("{}", port))
            .arg("--mnemonic")
            .arg("\"vast thought differ pull jewel broom cook wrist tribe word before omit\"")
            .spawn()
            .map_err(|e| {
                format!(
                    "Failed to start ganche-cli. \
                     Is it ganache-cli installed and available on $PATH? Error: {:?}",
                    e
                )
            })?;

        let stdout = child
            .stdout
            .ok_or_else(|| "Unable to get stdout for ganache child process")?;

        let start = Instant::now();
        let mut reader = BufReader::new(stdout);
        loop {
            if start + Duration::from_millis(GANACHE_STARTUP_TIMEOUT_MILLIS) <= Instant::now() {
                break Err(
                    "Timed out waiting for ganache to start. Is ganache-cli installed?".to_string(),
                );
            }

            let mut line = String::new();
            if let Err(e) = reader.read_line(&mut line) {
                break Err(format!("Failed to read line from ganache process: {:?}", e));
            } else if line.starts_with("Listening on") {
                break Ok(());
            } else {
                continue;
            }
        }?;

        let (event_loop, transport) = Http::new(&endpoint(port)).map_err(|e| {
            format!(
                "Failed to start HTTP transport connected to ganache: {:?}",
                e
            )
        })?;
        let web3 = Web3::new(transport);

        child.stdout = Some(reader.into_inner());

        Ok(Self {
            child,
            port,
            _event_loop: Arc::new(event_loop),
            web3,
        })
    }

    /// Returns the endpoint that this instance is listening on.
    pub fn endpoint(&self) -> String {
        endpoint(self.port)
    }

    /// Increase the timestamp on future blocks by `increase_by` seconds.
    pub fn increase_time(&self, increase_by: u64) -> impl Future<Item = (), Error = String> {
        self.web3
            .transport()
            .execute("evm_increaseTime", vec![json!(increase_by)])
            .map(|_json_value| ())
            .map_err(|e| format!("Failed to increase time on EVM (is this ganache?): {:?}", e))
    }

    /// Returns the current block number, as u64
    pub fn block_number(&self) -> impl Future<Item = u64, Error = String> {
        self.web3
            .eth()
            .block_number()
            .map(|v| v.as_u64())
            .map_err(|e| format!("Failed to get block number: {:?}", e))
    }

    /// Mines a single block.
    pub fn evm_mine(&self) -> impl Future<Item = (), Error = String> {
        self.web3
            .transport()
            .execute("evm_mine", vec![])
            .map(|_| ())
            .map_err(|_| {
                "utils should mine new block with evm_mine (only works with ganache-cli!)"
                    .to_string()
            })
    }
}

fn endpoint(port: u16) -> String {
    format!("http://localhost:{}", port)
}

/// A bit of hack to find an unused TCP port.
///
/// Does not guarantee that the given port is unused after the function exists, just that it was
/// unused before the function started (i.e., it does not reserve a port).
pub fn unused_port() -> Result<u16, String> {
    let listener = TcpListener::bind("127.0.0.1:0")
        .map_err(|e| format!("Failed to create TCP listener to find unused port: {:?}", e))?;

    let local_addr = listener.local_addr().map_err(|e| {
        format!(
            "Failed to read TCP listener local_addr to find unused port: {:?}",
            e
        )
    })?;

    Ok(local_addr.port())
}

impl Drop for GanacheInstance {
    fn drop(&mut self) {
        let _ = self.child.kill();
    }
}
<commit_msg>Correct typo (#872)<commit_after>use futures::Future;
use serde_json::json;
use std::io::prelude::*;
use std::io::BufReader;
use std::net::TcpListener;
use std::process::{Child, Command, Stdio};
use std::sync::Arc;
use std::time::{Duration, Instant};
use web3::{
    transports::{EventLoopHandle, Http},
    Transport, Web3,
};

/// How long we will wait for ganache to indicate that it is ready.
const GANACHE_STARTUP_TIMEOUT_MILLIS: u64 = 10_000;

/// Provides a dedicated `ganachi-cli` instance with a connected `Web3` instance.
///
/// Requires that `ganachi-cli` is installed and available on `PATH`.
pub struct GanacheInstance {
    pub port: u16,
    child: Child,
    _event_loop: Arc<EventLoopHandle>,
    pub web3: Web3<Http>,
}

impl GanacheInstance {
    /// Start a new `ganache-cli` process, waiting until it indicates that it is ready to accept
    /// RPC connections.
    pub fn new() -> Result<Self, String> {
        let port = unused_port()?;

        let mut child = Command::new("ganache-cli")
            .stdout(Stdio::piped())
            .arg("--defaultBalanceEther")
            .arg("1000000000")
            .arg("--gasLimit")
            .arg("1000000000")
            .arg("--accounts")
            .arg("10")
            .arg("--port")
            .arg(format!("{}", port))
            .arg("--mnemonic")
            .arg("\"vast thought differ pull jewel broom cook wrist tribe word before omit\"")
            .spawn()
            .map_err(|e| {
                format!(
                    "Failed to start ganache-cli. \
                     Is it ganache-cli installed and available on $PATH? Error: {:?}",
                    e
                )
            })?;

        let stdout = child
            .stdout
            .ok_or_else(|| "Unable to get stdout for ganache child process")?;

        let start = Instant::now();
        let mut reader = BufReader::new(stdout);
        loop {
            if start + Duration::from_millis(GANACHE_STARTUP_TIMEOUT_MILLIS) <= Instant::now() {
                break Err(
                    "Timed out waiting for ganache to start. Is ganache-cli installed?".to_string(),
                );
            }

            let mut line = String::new();
            if let Err(e) = reader.read_line(&mut line) {
                break Err(format!("Failed to read line from ganache process: {:?}", e));
            } else if line.starts_with("Listening on") {
                break Ok(());
            } else {
                continue;
            }
        }?;

        let (event_loop, transport) = Http::new(&endpoint(port)).map_err(|e| {
            format!(
                "Failed to start HTTP transport connected to ganache: {:?}",
                e
            )
        })?;
        let web3 = Web3::new(transport);

        child.stdout = Some(reader.into_inner());

        Ok(Self {
            child,
            port,
            _event_loop: Arc::new(event_loop),
            web3,
        })
    }

    /// Returns the endpoint that this instance is listening on.
    pub fn endpoint(&self) -> String {
        endpoint(self.port)
    }

    /// Increase the timestamp on future blocks by `increase_by` seconds.
    pub fn increase_time(&self, increase_by: u64) -> impl Future<Item = (), Error = String> {
        self.web3
            .transport()
            .execute("evm_increaseTime", vec![json!(increase_by)])
            .map(|_json_value| ())
            .map_err(|e| format!("Failed to increase time on EVM (is this ganache?): {:?}", e))
    }

    /// Returns the current block number, as u64
    pub fn block_number(&self) -> impl Future<Item = u64, Error = String> {
        self.web3
            .eth()
            .block_number()
            .map(|v| v.as_u64())
            .map_err(|e| format!("Failed to get block number: {:?}", e))
    }

    /// Mines a single block.
    pub fn evm_mine(&self) -> impl Future<Item = (), Error = String> {
        self.web3
            .transport()
            .execute("evm_mine", vec![])
            .map(|_| ())
            .map_err(|_| {
                "utils should mine new block with evm_mine (only works with ganache-cli!)"
                    .to_string()
            })
    }
}

fn endpoint(port: u16) -> String {
    format!("http://localhost:{}", port)
}

/// A bit of hack to find an unused TCP port.
///
/// Does not guarantee that the given port is unused after the function exists, just that it was
/// unused before the function started (i.e., it does not reserve a port).
pub fn unused_port() -> Result<u16, String> {
    let listener = TcpListener::bind("127.0.0.1:0")
        .map_err(|e| format!("Failed to create TCP listener to find unused port: {:?}", e))?;

    let local_addr = listener.local_addr().map_err(|e| {
        format!(
            "Failed to read TCP listener local_addr to find unused port: {:?}",
            e
        )
    })?;

    Ok(local_addr.port())
}

impl Drop for GanacheInstance {
    fn drop(&mut self) {
        let _ = self.child.kill();
    }
}
<|endoftext|>


<commit_before>#[cfg(any(feature = "socket", feature = "pipe"))]
use std::net::{Ipv4Addr, Ipv6Addr};

#[cfg(any(feature = "socket", feature = "ssl"))]
use std::path;

#[cfg(any(feature = "socket", feature = "pipe"))]
use std::str::FromStr;

use super::super::error::UrlError;

use url::{
    UrlParser,
    SchemeType,
};

/// Mysql connection options.
///
/// For example:
///
/// ```ignore
/// let opts = Opts {
///     user: Some("username".to_string()),
///     pass: Some("password".to_string()),
///     db_name: Some("mydatabase".to_string()),
///     ..Default::default()
/// };
/// ```
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct Opts {
    /// Address of mysql server (defaults to `127.0.0.1`). Hostnames should also work.
    pub ip_or_hostname: Option<String>,
    /// TCP port of mysql server (defaults to `3306`).
    pub tcp_port: u16,
    /// Path to unix socket of mysql server (defaults to `None`).
    #[cfg(feature = "socket")]
    pub unix_addr: Option<path::PathBuf>,
    /// Pipe name of mysql server (defaults to `None`).
    #[cfg(feature = "pipe")]
    pub pipe_name: Option<String>,
    /// User (defaults to `None`).
    pub user: Option<String>,
    /// Password (defaults to `None`).
    pub pass: Option<String>,
    /// Database name (defaults to `None`).
    pub db_name: Option<String>,

    #[cfg(any(feature = "socket", feature = "pipe"))]
    /// Prefer socket connection (defaults to `true`).
    ///
    /// Will reconnect via socket after TCP connection to `127.0.0.1` if `true`.
    pub prefer_socket: bool,
    // XXX: Wait for keepalive_timeout stabilization
    /// Commands to execute on each new database connection.
    pub init: Vec<String>,

    #[cfg(feature = "ssl")]
    /// #### Only available if `ssl` feature enabled.
    /// Perform or not ssl peer verification (defaults to `false`).
    /// Only make sense if ssl_opts is not None.
    pub verify_peer: bool,

    #[cfg(feature = "ssl")]
    /// #### Only available if `ssl` feature enabled.
    /// SSL certificates and keys in pem format.
    /// If not None, then ssl connection implied.
    ///
    /// `Option<(ca_cert, Option<(client_cert, client_key)>)>.`
    pub ssl_opts: Option<(path::PathBuf, Option<(path::PathBuf, path::PathBuf)>)>
}

impl Opts {
    #[doc(hidden)]
    #[cfg(any(feature = "socket", feature = "pipe"))]
    pub fn addr_is_loopback(&self) -> bool {
        if self.ip_or_hostname.is_some() {
            let v4addr: Option<Ipv4Addr> = FromStr::from_str(
                self.ip_or_hostname.as_ref().unwrap().as_ref()).ok();
            let v6addr: Option<Ipv6Addr> = FromStr::from_str(
                self.ip_or_hostname.as_ref().unwrap().as_ref()).ok();
            if let Some(addr) = v4addr {
                addr.octets()[0] == 127
            } else if let Some(addr) = v6addr {
                addr.segments() == [0, 0, 0, 0, 0, 0, 0, 1]
            } else if self.ip_or_hostname.as_ref().unwrap() == "localhost" {
                true
            } else {
                false
            }
        } else {
            false
        }
    }

    pub fn from_url(url: &str) -> Result<Opts, UrlError> {
        from_url(url)
    }

    #[cfg(any(feature = "socket", feature = "pipe"))]
    fn set_prefer_socket(&mut self, val: bool) {
        self.prefer_socket = val;
    }

    #[allow(unused_variables)]
    #[cfg(all(not(feature = "socket"), not(feature = "pipe")))]
    fn set_prefer_socket(&mut self, val: bool) {
        ()
    }

    #[cfg(feature = "ssl")]
    fn set_verify_peer(&mut self, val: bool) {
        self.verify_peer = val;
    }

    #[allow(unused_variables)]
    #[cfg(not(feature = "ssl"))]
    fn set_verify_peer(&mut self, val: bool) {
        ()
    }
}

#[cfg(all(not(feature = "ssl"), feature = "socket", not(feature = "pipe")))]
impl Default for Opts {
    fn default() -> Opts {
        Opts {
            ip_or_hostname: Some("127.0.0.1".to_string()),
            tcp_port: 3306,
            unix_addr: None,
            user: None,
            pass: None,
            db_name: None,
            prefer_socket: true,
            init: vec![],
        }
    }
}

#[cfg(all(not(feature = "ssl"), not(feature = "socket"), not(feature = "pipe")))]
impl Default for Opts {
    fn default() -> Opts {
        Opts {
            ip_or_hostname: Some("127.0.0.1".to_string()),
            tcp_port: 3306,
            user: None,
            pass: None,
            db_name: None,
            init: vec![],
        }
    }
}

#[cfg(all(not(feature = "ssl"), not(feature = "socket"), feature = "pipe"))]
impl Default for Opts {
    fn default() -> Opts {
        Opts {
            ip_or_hostname: Some("127.0.0.1".to_string()),
            tcp_port: 3306,
            pipe_name: None,
            user: None,
            pass: None,
            db_name: None,
            prefer_socket: true,
            init: vec![],
        }
    }
}

#[cfg(all(feature = "ssl", not(feature = "socket"), not(feature = "pipe")))]
impl Default for Opts {
    fn default() -> Opts {
        Opts {
            ip_or_hostname: Some("127.0.0.1".to_string()),
            tcp_port: 3306,
            user: None,
            pass: None,
            db_name: None,
            init: vec![],
            verify_peer: false,
            ssl_opts: None,
        }
    }
}

#[cfg(all(feature = "ssl", not(feature = "socket"), feature = "pipe"))]
impl Default for Opts {
    fn default() -> Opts {
        Opts {
            ip_or_hostname: Some("127.0.0.1".to_string()),
            tcp_port: 3306,
            pipe_name: None,
            user: None,
            pass: None,
            db_name: None,
            init: vec![],
            verify_peer: false,
            prefer_socket: true,
            ssl_opts: None,
        }
    }
}

#[cfg(all(feature = "ssl", feature = "socket", not(feature = "pipe")))]
impl Default for Opts {
    fn default() -> Opts {
        Opts {
            ip_or_hostname: Some("127.0.0.1".to_string()),
            tcp_port: 3306,
            unix_addr: None,
            user: None,
            pass: None,
            db_name: None,
            prefer_socket: true,
            init: vec![],
            verify_peer: false,
            ssl_opts: None,
        }
    }
}

fn from_url_basic(url: &str) -> Result<(Opts, Vec<(String, String)>), UrlError> {
    fn scheme_type_mapper(scheme: &str) -> SchemeType {
        match scheme {
            "mysql" => SchemeType::Relative(3306),
            _ => SchemeType::NonRelative,
        }
    }

    let mut parser = UrlParser::new();
    parser.scheme_type_mapper(scheme_type_mapper);
    let url = try!(parser.parse(url));
    if url.scheme != "mysql" {
        return Err(UrlError::UnsupportedScheme(url.scheme))
    }
    let user = url.lossy_percent_decode_username();
    let pass = url.lossy_percent_decode_password();
    let ip_or_hostname = match url.domain() {
        Some(domain) => Some(domain.to_string()),
        None => Some("127.0.0.1".to_string()),
    };
    let tcp_port = url.port().unwrap_or(3306);
    let db_name = match url.path() {
        Some(path) => {
            if path.len() > 0 {
                Some(path[0].clone())
            } else {
                None
            }
        },
        None => None,
    };
    let query_pairs = url.query_pairs().unwrap_or(Vec::new());
    let opts = Opts {
        user: user,
        pass: pass,
        ip_or_hostname: ip_or_hostname,
        tcp_port: tcp_port,
        db_name: db_name,
        ..Opts::default()
    };
    Ok((opts, query_pairs))
}

fn from_url(url: &str) -> Result<Opts, UrlError> {
    let (mut opts, query_pairs) = try!(from_url_basic(url));
    for (key, value) in query_pairs {
        if key == "prefer_socket" {
            if cfg!(all(not(feature = "socket"), not(feature = "pipe"))) {
                return Err(
                    UrlError::FeatureRequired("`socket' or `pipe'".into(), "prefer_socket".into())
                );
            } else {
                if value == "true" {
                    opts.set_prefer_socket(true);
                } else if value == "false" {
                    opts.set_prefer_socket(false);
                } else {
                    return Err(UrlError::InvalidValue("prefer_socket".into(), value));
                }
            }
        } else if key == "verify_peer" {
            if cfg!(not(feature = "ssl")) {
                return Err(UrlError::FeatureRequired("`ssl'".into(), "verify_peer".into()));
            } else {
                if value == "true" {
                    opts.set_verify_peer(true);
                } else if value == "false" {
                    opts.set_verify_peer(false);
                } else {
                    return Err(UrlError::InvalidValue("verify_peer".into(), value));
                }
            }
        } else {
            return Err(UrlError::UnknownParameter(key));
        }
    }
    Ok(opts)
}

impl<'a> From<&'a str> for Opts {
    fn from(url: &'a str) -> Opts {
        match from_url(url) {
            Ok(opts) => opts,
            Err(err) => panic!("{}", err),
        }
    }
}

#[cfg(test)]
mod test {
    use super::Opts;

    #[test]
    #[cfg(all(feature = "ssl", feature = "socket"))]
    fn should_convert_url_into_opts() {
        let opts = "mysql://usr:pw@localhost:3308/dbname?prefer_socket=false&verify_peer=true";
        assert_eq!(Opts {
            user: Some("usr".to_string()),
            pass: Some("pw".to_string()),
            ip_or_hostname: Some("localhost".to_string()),
            tcp_port: 3308,
            db_name: Some("dbname".to_string()),
            prefer_socket: false,
            verify_peer: true,
            ..Opts::default()
        }, opts.into());
    }

    #[test]
    #[cfg(all(not(feature = "ssl"), not(feature = "socket")))]
    fn should_convert_url_into_opts() {
        let opts = "mysql://usr:pw@localhost:3308/dbname";
        assert_eq!(Opts {
            user: Some("usr".to_string()),
            pass: Some("pw".to_string()),
            ip_or_hostname: Some("localhost".to_string()),
            tcp_port: 3308,
            db_name: Some("dbname".to_string()),
            ..Opts::default()
        }, opts.into());
    }

    #[test]
    #[should_panic]
    fn should_panic_on_invalid_url() {
        let opts = "42";
        let _: Opts = opts.into();
    }

    #[test]
    #[should_panic]
    fn should_panic_on_invalid_scheme() {
        let opts = "postgres://localhost";
        let _: Opts = opts.into();
    }

    #[test]
    #[should_panic]
    fn should_panic_on_unknown_query_param() {
        let opts = "mysql://localhost/foo?bar=baz";
        let _: Opts = opts.into();
    }

    #[test]
    #[should_panic]
    #[cfg(not(feature = "socket"))]
    fn should_panic_if_prefer_socket_query_param_requires_feature() {
        let opts = "mysql://usr:pw@localhost:3308/dbname?prefer_socket=false";
        let _: Opts = opts.into();
    }

    #[test]
    #[should_panic]
    #[cfg(not(feature = "ssl"))]
    fn should_panic_if_verify_peer_query_param_requires_feature() {
        let opts = "mysql://usr:pw@localhost:3308/dbname?verify_peer=false";
        let _: Opts = opts.into();
    }

    #[test]
    #[should_panic]
    #[cfg(feature = "socket")]
    fn should_panic_on_invalid_prefer_socket_param_value() {
        let opts = "mysql://usr:pw@localhost:3308/dbname?prefer_socket=invalid";
        let _: Opts = opts.into();
    }

    #[test]
    #[should_panic]
    #[cfg(feature = "ssl")]
    fn should_panic_on_invalid_verify_peer_param_value() {
        let opts = "mysql://usr:pw@localhost:3308/dbname?verify_peer=invalid";
        let _: Opts = opts.into();
    }

    #[test]
    #[should_panic]
    #[cfg(all(not(feature = "ssl"), not(feature = "socket")))]
    fn should_panic_on_unk() {
        let opts = "mysql://localhost/dbname?prefer_socket=false";
        assert_eq!(Opts {
            user: Some("usr".to_string()),
            pass: Some("pw".to_string()),
            ip_or_hostname: Some("localhost".to_string()),
            tcp_port: 3308,
            db_name: Some("dbname".to_string()),
            ..Opts::default()
        }, opts.into());
    }
}
<commit_msg>Use stabilized `is_loopback`<commit_after>#[cfg(any(feature = "socket", feature = "pipe"))]
use std::net::{Ipv4Addr, Ipv6Addr};

#[cfg(any(feature = "socket", feature = "ssl"))]
use std::path;

#[cfg(any(feature = "socket", feature = "pipe"))]
use std::str::FromStr;

use super::super::error::UrlError;

use url::{
    UrlParser,
    SchemeType,
};

/// Mysql connection options.
///
/// For example:
///
/// ```ignore
/// let opts = Opts {
///     user: Some("username".to_string()),
///     pass: Some("password".to_string()),
///     db_name: Some("mydatabase".to_string()),
///     ..Default::default()
/// };
/// ```
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct Opts {
    /// Address of mysql server (defaults to `127.0.0.1`). Hostnames should also work.
    pub ip_or_hostname: Option<String>,
    /// TCP port of mysql server (defaults to `3306`).
    pub tcp_port: u16,
    /// Path to unix socket of mysql server (defaults to `None`).
    #[cfg(feature = "socket")]
    pub unix_addr: Option<path::PathBuf>,
    /// Pipe name of mysql server (defaults to `None`).
    #[cfg(feature = "pipe")]
    pub pipe_name: Option<String>,
    /// User (defaults to `None`).
    pub user: Option<String>,
    /// Password (defaults to `None`).
    pub pass: Option<String>,
    /// Database name (defaults to `None`).
    pub db_name: Option<String>,

    #[cfg(any(feature = "socket", feature = "pipe"))]
    /// Prefer socket connection (defaults to `true`).
    ///
    /// Will reconnect via socket after TCP connection to `127.0.0.1` if `true`.
    pub prefer_socket: bool,
    // XXX: Wait for keepalive_timeout stabilization
    /// Commands to execute on each new database connection.
    pub init: Vec<String>,

    #[cfg(feature = "ssl")]
    /// #### Only available if `ssl` feature enabled.
    /// Perform or not ssl peer verification (defaults to `false`).
    /// Only make sense if ssl_opts is not None.
    pub verify_peer: bool,

    #[cfg(feature = "ssl")]
    /// #### Only available if `ssl` feature enabled.
    /// SSL certificates and keys in pem format.
    /// If not None, then ssl connection implied.
    ///
    /// `Option<(ca_cert, Option<(client_cert, client_key)>)>.`
    pub ssl_opts: Option<(path::PathBuf, Option<(path::PathBuf, path::PathBuf)>)>
}

impl Opts {
    #[doc(hidden)]
    #[cfg(any(feature = "socket", feature = "pipe"))]
    pub fn addr_is_loopback(&self) -> bool {
        if self.ip_or_hostname.is_some() {
            let v4addr: Option<Ipv4Addr> = FromStr::from_str(
                self.ip_or_hostname.as_ref().unwrap().as_ref()).ok();
            let v6addr: Option<Ipv6Addr> = FromStr::from_str(
                self.ip_or_hostname.as_ref().unwrap().as_ref()).ok();
            if let Some(addr) = v4addr {
                addr.is_loopback()
            } else if let Some(addr) = v6addr {
                addr.is_loopback()
            } else if self.ip_or_hostname.as_ref().unwrap() == "localhost" {
                true
            } else {
                false
            }
        } else {
            false
        }
    }

    pub fn from_url(url: &str) -> Result<Opts, UrlError> {
        from_url(url)
    }

    #[cfg(any(feature = "socket", feature = "pipe"))]
    fn set_prefer_socket(&mut self, val: bool) {
        self.prefer_socket = val;
    }

    #[allow(unused_variables)]
    #[cfg(all(not(feature = "socket"), not(feature = "pipe")))]
    fn set_prefer_socket(&mut self, val: bool) {
        ()
    }

    #[cfg(feature = "ssl")]
    fn set_verify_peer(&mut self, val: bool) {
        self.verify_peer = val;
    }

    #[allow(unused_variables)]
    #[cfg(not(feature = "ssl"))]
    fn set_verify_peer(&mut self, val: bool) {
        ()
    }
}

#[cfg(all(not(feature = "ssl"), feature = "socket", not(feature = "pipe")))]
impl Default for Opts {
    fn default() -> Opts {
        Opts {
            ip_or_hostname: Some("127.0.0.1".to_string()),
            tcp_port: 3306,
            unix_addr: None,
            user: None,
            pass: None,
            db_name: None,
            prefer_socket: true,
            init: vec![],
        }
    }
}

#[cfg(all(not(feature = "ssl"), not(feature = "socket"), not(feature = "pipe")))]
impl Default for Opts {
    fn default() -> Opts {
        Opts {
            ip_or_hostname: Some("127.0.0.1".to_string()),
            tcp_port: 3306,
            user: None,
            pass: None,
            db_name: None,
            init: vec![],
        }
    }
}

#[cfg(all(not(feature = "ssl"), not(feature = "socket"), feature = "pipe"))]
impl Default for Opts {
    fn default() -> Opts {
        Opts {
            ip_or_hostname: Some("127.0.0.1".to_string()),
            tcp_port: 3306,
            pipe_name: None,
            user: None,
            pass: None,
            db_name: None,
            prefer_socket: true,
            init: vec![],
        }
    }
}

#[cfg(all(feature = "ssl", not(feature = "socket"), not(feature = "pipe")))]
impl Default for Opts {
    fn default() -> Opts {
        Opts {
            ip_or_hostname: Some("127.0.0.1".to_string()),
            tcp_port: 3306,
            user: None,
            pass: None,
            db_name: None,
            init: vec![],
            verify_peer: false,
            ssl_opts: None,
        }
    }
}

#[cfg(all(feature = "ssl", not(feature = "socket"), feature = "pipe"))]
impl Default for Opts {
    fn default() -> Opts {
        Opts {
            ip_or_hostname: Some("127.0.0.1".to_string()),
            tcp_port: 3306,
            pipe_name: None,
            user: None,
            pass: None,
            db_name: None,
            init: vec![],
            verify_peer: false,
            prefer_socket: true,
            ssl_opts: None,
        }
    }
}

#[cfg(all(feature = "ssl", feature = "socket", not(feature = "pipe")))]
impl Default for Opts {
    fn default() -> Opts {
        Opts {
            ip_or_hostname: Some("127.0.0.1".to_string()),
            tcp_port: 3306,
            unix_addr: None,
            user: None,
            pass: None,
            db_name: None,
            prefer_socket: true,
            init: vec![],
            verify_peer: false,
            ssl_opts: None,
        }
    }
}

fn from_url_basic(url: &str) -> Result<(Opts, Vec<(String, String)>), UrlError> {
    fn scheme_type_mapper(scheme: &str) -> SchemeType {
        match scheme {
            "mysql" => SchemeType::Relative(3306),
            _ => SchemeType::NonRelative,
        }
    }

    let mut parser = UrlParser::new();
    parser.scheme_type_mapper(scheme_type_mapper);
    let url = try!(parser.parse(url));
    if url.scheme != "mysql" {
        return Err(UrlError::UnsupportedScheme(url.scheme))
    }
    let user = url.lossy_percent_decode_username();
    let pass = url.lossy_percent_decode_password();
    let ip_or_hostname = match url.domain() {
        Some(domain) => Some(domain.to_string()),
        None => Some("127.0.0.1".to_string()),
    };
    let tcp_port = url.port().unwrap_or(3306);
    let db_name = match url.path() {
        Some(path) => {
            if path.len() > 0 {
                Some(path[0].clone())
            } else {
                None
            }
        },
        None => None,
    };
    let query_pairs = url.query_pairs().unwrap_or(Vec::new());
    let opts = Opts {
        user: user,
        pass: pass,
        ip_or_hostname: ip_or_hostname,
        tcp_port: tcp_port,
        db_name: db_name,
        ..Opts::default()
    };
    Ok((opts, query_pairs))
}

fn from_url(url: &str) -> Result<Opts, UrlError> {
    let (mut opts, query_pairs) = try!(from_url_basic(url));
    for (key, value) in query_pairs {
        if key == "prefer_socket" {
            if cfg!(all(not(feature = "socket"), not(feature = "pipe"))) {
                return Err(
                    UrlError::FeatureRequired("`socket' or `pipe'".into(), "prefer_socket".into())
                );
            } else {
                if value == "true" {
                    opts.set_prefer_socket(true);
                } else if value == "false" {
                    opts.set_prefer_socket(false);
                } else {
                    return Err(UrlError::InvalidValue("prefer_socket".into(), value));
                }
            }
        } else if key == "verify_peer" {
            if cfg!(not(feature = "ssl")) {
                return Err(UrlError::FeatureRequired("`ssl'".into(), "verify_peer".into()));
            } else {
                if value == "true" {
                    opts.set_verify_peer(true);
                } else if value == "false" {
                    opts.set_verify_peer(false);
                } else {
                    return Err(UrlError::InvalidValue("verify_peer".into(), value));
                }
            }
        } else {
            return Err(UrlError::UnknownParameter(key));
        }
    }
    Ok(opts)
}

impl<'a> From<&'a str> for Opts {
    fn from(url: &'a str) -> Opts {
        match from_url(url) {
            Ok(opts) => opts,
            Err(err) => panic!("{}", err),
        }
    }
}

#[cfg(test)]
mod test {
    use super::Opts;

    #[test]
    #[cfg(all(feature = "ssl", feature = "socket"))]
    fn should_convert_url_into_opts() {
        let opts = "mysql://usr:pw@localhost:3308/dbname?prefer_socket=false&verify_peer=true";
        assert_eq!(Opts {
            user: Some("usr".to_string()),
            pass: Some("pw".to_string()),
            ip_or_hostname: Some("localhost".to_string()),
            tcp_port: 3308,
            db_name: Some("dbname".to_string()),
            prefer_socket: false,
            verify_peer: true,
            ..Opts::default()
        }, opts.into());
    }

    #[test]
    #[cfg(all(not(feature = "ssl"), not(feature = "socket")))]
    fn should_convert_url_into_opts() {
        let opts = "mysql://usr:pw@localhost:3308/dbname";
        assert_eq!(Opts {
            user: Some("usr".to_string()),
            pass: Some("pw".to_string()),
            ip_or_hostname: Some("localhost".to_string()),
            tcp_port: 3308,
            db_name: Some("dbname".to_string()),
            ..Opts::default()
        }, opts.into());
    }

    #[test]
    #[should_panic]
    fn should_panic_on_invalid_url() {
        let opts = "42";
        let _: Opts = opts.into();
    }

    #[test]
    #[should_panic]
    fn should_panic_on_invalid_scheme() {
        let opts = "postgres://localhost";
        let _: Opts = opts.into();
    }

    #[test]
    #[should_panic]
    fn should_panic_on_unknown_query_param() {
        let opts = "mysql://localhost/foo?bar=baz";
        let _: Opts = opts.into();
    }

    #[test]
    #[should_panic]
    #[cfg(not(feature = "socket"))]
    fn should_panic_if_prefer_socket_query_param_requires_feature() {
        let opts = "mysql://usr:pw@localhost:3308/dbname?prefer_socket=false";
        let _: Opts = opts.into();
    }

    #[test]
    #[should_panic]
    #[cfg(not(feature = "ssl"))]
    fn should_panic_if_verify_peer_query_param_requires_feature() {
        let opts = "mysql://usr:pw@localhost:3308/dbname?verify_peer=false";
        let _: Opts = opts.into();
    }

    #[test]
    #[should_panic]
    #[cfg(feature = "socket")]
    fn should_panic_on_invalid_prefer_socket_param_value() {
        let opts = "mysql://usr:pw@localhost:3308/dbname?prefer_socket=invalid";
        let _: Opts = opts.into();
    }

    #[test]
    #[should_panic]
    #[cfg(feature = "ssl")]
    fn should_panic_on_invalid_verify_peer_param_value() {
        let opts = "mysql://usr:pw@localhost:3308/dbname?verify_peer=invalid";
        let _: Opts = opts.into();
    }

    #[test]
    #[should_panic]
    #[cfg(all(not(feature = "ssl"), not(feature = "socket")))]
    fn should_panic_on_unk() {
        let opts = "mysql://localhost/dbname?prefer_socket=false";
        assert_eq!(Opts {
            user: Some("usr".to_string()),
            pass: Some("pw".to_string()),
            ip_or_hostname: Some("localhost".to_string()),
            tcp_port: 3308,
            db_name: Some("dbname".to_string()),
            ..Opts::default()
        }, opts.into());
    }
}
<|endoftext|>


<commit_before>use std::ops::{Deref, DerefMut};
use rustwlc::Geometry;
use super::super::borders::Borders;
use ::render::{BaseDraw, Drawable, DrawErr};
use super::super::container::Layout;

/// Draws the borders around the container.
/// The only borders that are drawn are for the title bars, as the individual
/// edge borders are handled by the child views.
pub struct ContainerDraw {
    base: BaseDraw<Borders>,
}

impl ContainerDraw {
    pub fn new(base: BaseDraw<Borders>) -> Self {
        ContainerDraw {
            base
        }
    }

    fn draw_title_bar(mut self,
                      mut x: f64,
                      mut w: f64,) -> Result<Self, DrawErr<Borders>> {
        let gap = Borders::gap_size() as f64;
        let title_size = self.base.inner().title_bar_size() as f64;
        let title_color = self.base.inner().title_background_color();
        let title_font_color = self.base.inner().title_font_color();
        if x < 0.0 {
            w += x;
        }
        let title_x = Borders::thickness() as f64 + gap / 2.0;
        let title_y = title_size - 5.0;
        x = gap / 2.0;
        w -= gap;

        // Children data necessary for tabbed and stacked containers
        let child_data = self.base.inner().children.as_ref().map(
            |children| (children.titles.len(), children.index)
        );

        // For some reason, when changing a container to be tabbed or stacked,
        // the borders are drawn when the layout is set but the children are
        // not, so the layout being Tabbed/Stacked doesn't guarantee having
        // the children information.
        match (self.base.inner().layout, child_data) {
            (Some(Layout::Tabbed), Some((child_count, active_index))) => {

                let tab_width = w / child_count as f64;

                // Iterate over the indices to not borrow self
                for i in 0..child_count {
                    let active = Some(i) == active_index;

                    let title_color = if active { title_color }
                        else { Borders::default_title_color() };

                    let title_font_color = if active { title_font_color }
                        else { Borders::default_title_font_color() };

                    let x = x + tab_width*i as f64;
                    let title_x = title_x + tab_width*i as f64;

                    // Draw background of title bar
                    self.base.set_source_rgb(1.0, 0.0, 0.0);
                    self.base.set_color_source(title_color);
                    self.base.rectangle(x, 0.0, tab_width, title_size);
                    self.base = try!(self.base.check_cairo());
                    self.base.fill();
                    self.base = try!(self.base.check_cairo());

                    // Draw title text
                    self.base.move_to(title_x, title_y);
                    self.base = try!(self.base.check_cairo());
                    self.base.set_color_source(title_font_color);
                    self.base = try!(self.base.check_cairo());
                    self.base.show_text(
                        match self.base.inner().children.as_ref() {
                            Some(children) => children.titles[i].as_str(),
                            None => unreachable!()
                        }
                    );
                    self.base = try!(self.base.check_cairo());
                }
            }
            (Some(Layout::Stacked), Some((child_count, active_index))) => {

                // Iterate over the indices to not borrow self
                for i in 0..child_count {
                    let active = Some(i) == active_index;

                    let title_color = if active { title_color }
                        else { Borders::default_title_color() };

                    let title_font_color = if active { title_font_color }
                        else { Borders::default_title_font_color() };

                    let y = title_size*i as f64;
                    let title_y = title_y as f64 + y;

                    // Draw background of title bar
                    self.base.set_source_rgb(1.0, 0.0, 0.0);
                    self.base.set_color_source(title_color);
                    self.base.rectangle(x, y, w, title_size);
                    self.base = try!(self.base.check_cairo());
                    self.base.fill();
                    self.base = try!(self.base.check_cairo());

                    // Draw title text
                    self.base.move_to(title_x, title_y);
                    self.base = try!(self.base.check_cairo());
                    self.base.set_color_source(title_font_color);
                    self.base = try!(self.base.check_cairo());
                    self.base.show_text(
                        match self.base.inner().children.as_ref() {
                            Some(children) => children.titles[i].as_str(),
                            None => unreachable!()
                        }
                    );
                    self.base = try!(self.base.check_cairo());
                }
            }
            _ => {
                // Draw background of title bar
                self.base.set_source_rgb(1.0, 0.0, 0.0);
                self.base.set_color_source(title_color);
                self.base.rectangle(x, 0.0, w, title_size);
                self.base = try!(self.base.check_cairo());
                self.base.fill();
                self.base = try!(self.base.check_cairo());

                // Draw title text
                self.base.move_to(title_x, title_y);
                self.base = try!(self.base.check_cairo());
                self.base.set_color_source(title_font_color);
                self.base = try!(self.base.check_cairo());
                self.base.show_text(self.inner().title());
                self.base = try!(self.base.check_cairo());
            }
        }

        Ok(self)
    }
}

impl Drawable<Borders> for ContainerDraw {
    // Draw the title bar around the container
    fn draw(mut self, container_g: Geometry) -> Result<Borders, DrawErr<Borders>> {
        let mut border_g = container_g;
        let thickness = Borders::thickness();

        let title_count = match (self.inner().layout, &self.inner().children) {
            (Some(Layout::Stacked), &Some(ref children)) =>
                // I don't understand why I have to use this
                // instead of just child_count, but seems to work...
                (2 * children.titles.len()).saturating_sub(1) as u32,
            _ => 1
        };

        let title_size = self.base.inner().title_bar_size() * title_count;
        let edge_thickness = thickness / 2;

        border_g.origin.x -= edge_thickness as i32;
        border_g.origin.y -= edge_thickness as i32;
        border_g.origin.y -= (title_size / 2) as i32;
        border_g.size.w += thickness;
        border_g.size.h = edge_thickness + title_size/2;

        self.base.set_source_rgba(0.0, 0.0, 0.0, 0.0);
        self.base.paint();
        let color = self.base.inner().color();
        self.base.set_color_source(color);

        let (x, w) = (border_g.origin.x as f64,
                      border_g.size.w as f64);
        self = self.draw_title_bar(x, w)?;
        Ok(self.base.finish(border_g))
    }
}

impl Deref for ContainerDraw {
    type Target = BaseDraw<Borders>;

    fn deref(&self) -> &BaseDraw<Borders> {
        &self.base
    }
}

impl DerefMut for ContainerDraw {
    fn deref_mut(&mut self) -> &mut BaseDraw<Borders> {
        &mut self.base
    }
}
<commit_msg>Fixed title spacing issue<commit_after>use std::ops::{Deref, DerefMut};
use rustwlc::Geometry;
use super::super::borders::Borders;
use ::render::{BaseDraw, Drawable, DrawErr};
use super::super::container::Layout;

/// Draws the borders around the container.
/// The only borders that are drawn are for the title bars, as the individual
/// edge borders are handled by the child views.
pub struct ContainerDraw {
    base: BaseDraw<Borders>,
}

impl ContainerDraw {
    pub fn new(base: BaseDraw<Borders>) -> Self {
        ContainerDraw {
            base
        }
    }

    fn draw_title_bar(mut self,
                      mut x: f64,
                      mut w: f64,) -> Result<Self, DrawErr<Borders>> {
        let gap = Borders::gap_size() as f64;
        let title_size = self.base.inner().title_bar_size() as f64;
        let title_color = self.base.inner().title_background_color();
        let title_font_color = self.base.inner().title_font_color();
        if x < 0.0 {
            w += x;
        }
        let title_x = Borders::thickness() as f64 + gap / 2.0;
        let mut border_diff = Borders::thickness().saturating_sub(title_size as u32);
        if border_diff == 0 {
            border_diff = (title_size as u32).saturating_sub(Borders::thickness());
        }
        if border_diff < 5 {
            border_diff = 5
        }
        let title_y = title_size - border_diff as f64;
        x = gap / 2.0;
        w -= gap;

        // Children data necessary for tabbed and stacked containers
        let child_data = self.base.inner().children.as_ref().map(
            |children| (children.titles.len(), children.index)
        );

        // For some reason, when changing a container to be tabbed or stacked,
        // the borders are drawn when the layout is set but the children are
        // not, so the layout being Tabbed/Stacked doesn't guarantee having
        // the children information.
        match (self.base.inner().layout, child_data) {
            (Some(Layout::Tabbed), Some((child_count, active_index))) => {

                let tab_width = w / child_count as f64;

                // Iterate over the indices to not borrow self
                for i in 0..child_count {
                    let active = Some(i) == active_index;

                    let title_color = if active { title_color }
                        else { Borders::default_title_color() };

                    let title_font_color = if active { title_font_color }
                        else { Borders::default_title_font_color() };

                    let x = x + tab_width*i as f64;
                    let title_x = title_x + tab_width*i as f64;

                    // Draw background of title bar
                    self.base.set_source_rgb(1.0, 0.0, 0.0);
                    self.base.set_color_source(title_color);
                    self.base.rectangle(x, 0.0, tab_width, title_size);
                    self.base = try!(self.base.check_cairo());
                    self.base.fill();
                    self.base = try!(self.base.check_cairo());

                    // Draw title text
                    self.base.move_to(title_x, title_y);
                    self.base = try!(self.base.check_cairo());
                    self.base.set_color_source(title_font_color);
                    self.base = try!(self.base.check_cairo());
                    self.base.show_text(
                        match self.base.inner().children.as_ref() {
                            Some(children) => children.titles[i].as_str(),
                            None => unreachable!()
                        }
                    );
                    self.base = try!(self.base.check_cairo());
                }
            }
            (Some(Layout::Stacked), Some((child_count, active_index))) => {

                // Iterate over the indices to not borrow self
                for i in 0..child_count {
                    let active = Some(i) == active_index;

                    let title_color = if active { title_color }
                        else { Borders::default_title_color() };

                    let title_font_color = if active { title_font_color }
                        else { Borders::default_title_font_color() };

                    let y = title_size*i as f64;
                    let title_y = title_y as f64 + y;

                    // Draw background of title bar
                    self.base.set_source_rgb(1.0, 0.0, 0.0);
                    self.base.set_color_source(title_color);
                    self.base.rectangle(x, y, w, title_size);
                    self.base = try!(self.base.check_cairo());
                    self.base.fill();
                    self.base = try!(self.base.check_cairo());

                    // Draw title text
                    self.base.move_to(title_x, title_y);
                    self.base = try!(self.base.check_cairo());
                    self.base.set_color_source(title_font_color);
                    self.base = try!(self.base.check_cairo());
                    self.base.show_text(
                        match self.base.inner().children.as_ref() {
                            Some(children) => children.titles[i].as_str(),
                            None => unreachable!()
                        }
                    );
                    self.base = try!(self.base.check_cairo());
                }
            }
            _ => {
                // Draw background of title bar
                self.base.set_source_rgb(1.0, 0.0, 0.0);
                self.base.set_color_source(title_color);
                self.base.rectangle(x, 0.0, w, title_size);
                self.base = try!(self.base.check_cairo());
                self.base.fill();
                self.base = try!(self.base.check_cairo());

                // Draw title text
                self.base.move_to(title_x, title_y);
                self.base = try!(self.base.check_cairo());
                self.base.set_color_source(title_font_color);
                self.base = try!(self.base.check_cairo());
                self.base.show_text(self.inner().title());
                self.base = try!(self.base.check_cairo());
            }
        }

        Ok(self)
    }
}

impl Drawable<Borders> for ContainerDraw {
    // Draw the title bar around the container
    fn draw(mut self, container_g: Geometry) -> Result<Borders, DrawErr<Borders>> {
        let mut border_g = container_g;
        let thickness = Borders::thickness();

        let title_count = match (self.inner().layout, &self.inner().children) {
            (Some(Layout::Stacked), &Some(ref children)) =>
                // I don't understand why I have to use this
                // instead of just child_count, but seems to work...
                (2 * children.titles.len()).saturating_sub(1) as u32,
            _ => 1
        };

        let title_size = self.base.inner().title_bar_size() * title_count;
        let edge_thickness = thickness / 2;

        border_g.origin.x -= edge_thickness as i32;
        border_g.origin.y -= edge_thickness as i32;
        border_g.origin.y -= (title_size / 2) as i32;
        border_g.size.w += thickness;
        border_g.size.h = edge_thickness + title_size/2;

        self.base.set_source_rgba(0.0, 0.0, 0.0, 0.0);
        self.base.paint();
        let color = self.base.inner().color();
        self.base.set_color_source(color);

        let (x, w) = (border_g.origin.x as f64,
                      border_g.size.w as f64);
        self = self.draw_title_bar(x, w)?;
        Ok(self.base.finish(border_g))
    }
}

impl Deref for ContainerDraw {
    type Target = BaseDraw<Borders>;

    fn deref(&self) -> &BaseDraw<Borders> {
        &self.base
    }
}

impl DerefMut for ContainerDraw {
    fn deref_mut(&mut self) -> &mut BaseDraw<Borders> {
        &mut self.base
    }
}
<|endoftext|>