<commit_before>use crate::{
    message::BasicReturnMessage,
    pinky_swear::{PinkyBroadcaster, PinkySwear},
    publisher_confirm::Confirmation,
    BasicProperties,
};
use log::error;
use parking_lot::Mutex;
use std::{collections::VecDeque, sync::Arc};

#[derive(Clone, Debug, Default)]
pub(crate) struct ReturnedMessages {
    inner: Arc<Mutex<Inner>>,
}

impl ReturnedMessages {
    pub(crate) fn start_new_delivery(&self, message: BasicReturnMessage) {
        self.inner.lock().current_message = Some(message);
    }

    pub(crate) fn set_delivery_properties(&self, properties: BasicProperties) {
        if let Some(message) = self.inner.lock().current_message.as_mut() {
            message.delivery.properties = properties;
        }
    }

    pub(crate) fn new_delivery_complete(&self) {
        self.inner.lock().new_delivery_complete();
    }

    pub(crate) fn receive_delivery_content(&self, data: Vec<u8>) {
        if let Some(message) = self.inner.lock().current_message.as_mut() {
            message.delivery.data.extend(data);
        }
    }

    pub(crate) fn drain(&self) -> Vec<BasicReturnMessage> {
        self.inner.lock().drain()
    }

    pub(crate) fn register_pinky(&self, pinky: PinkyBroadcaster<Confirmation>) {
        self.inner.lock().register_pinky(pinky);
    }

    pub(crate) fn register_dropped_confirm(&self, promise: PinkySwear<Confirmation>) {
        self.inner.lock().dropped_confirms.push(promise);
    }
}

#[derive(Debug, Default)]
pub struct Inner {
    current_message: Option<BasicReturnMessage>,
    messages: VecDeque<BasicReturnMessage>,
    dropped_confirms: Vec<PinkySwear<Confirmation>>,
    pinkies: VecDeque<PinkyBroadcaster<Confirmation>>,
}

impl Inner {
    fn register_pinky(&mut self, pinky: PinkyBroadcaster<Confirmation>) {
        if let Some(message) = self.messages.pop_front() {
            pinky.swear(Confirmation::Nack(message));
        } else {
            self.pinkies.push_back(pinky);
        }
    }

    fn new_delivery_complete(&mut self) {
        if let Some(message) = self.current_message.take() {
            error!("Server returned us a message: {:?}", message);
            if let Some(pinky) = self.pinkies.pop_front() {
                pinky.swear(Confirmation::Nack(message));
            } else {
                self.messages.push_back(message);
            }
        }
    }

    fn drain(&mut self) -> Vec<BasicReturnMessage> {
        let mut messages = Vec::default();
        for promise in self
            .dropped_confirms
            .drain(..)
            .collect::<Vec<PinkySwear<Confirmation>>>()
        {
            if let Some(confirmation) = promise.try_wait() {
                if let Confirmation::Nack(message) = confirmation {
                    messages.push(message);
                }
            } else {
                self.dropped_confirms.push(promise);
            }
        }
        messages
    }
}
<commit_msg>don't store unneeded promises<commit_after>use crate::{
    message::BasicReturnMessage,
    pinky_swear::{PinkyBroadcaster, PinkySwear},
    publisher_confirm::Confirmation,
    BasicProperties,
};
use log::error;
use parking_lot::Mutex;
use std::{collections::VecDeque, sync::Arc};

#[derive(Clone, Debug, Default)]
pub(crate) struct ReturnedMessages {
    inner: Arc<Mutex<Inner>>,
}

impl ReturnedMessages {
    pub(crate) fn start_new_delivery(&self, message: BasicReturnMessage) {
        self.inner.lock().current_message = Some(message);
    }

    pub(crate) fn set_delivery_properties(&self, properties: BasicProperties) {
        if let Some(message) = self.inner.lock().current_message.as_mut() {
            message.delivery.properties = properties;
        }
    }

    pub(crate) fn new_delivery_complete(&self) {
        self.inner.lock().new_delivery_complete();
    }

    pub(crate) fn receive_delivery_content(&self, data: Vec<u8>) {
        if let Some(message) = self.inner.lock().current_message.as_mut() {
            message.delivery.data.extend(data);
        }
    }

    pub(crate) fn drain(&self) -> Vec<BasicReturnMessage> {
        self.inner.lock().drain()
    }

    pub(crate) fn register_pinky(&self, pinky: PinkyBroadcaster<Confirmation>) {
        self.inner.lock().register_pinky(pinky);
    }

    pub(crate) fn register_dropped_confirm(&self, promise: PinkySwear<Confirmation>) {
        self.inner.lock().register_dropped_confirm(promise);
    }
}

#[derive(Debug, Default)]
pub struct Inner {
    current_message: Option<BasicReturnMessage>,
    waiting_messages: VecDeque<BasicReturnMessage>,
    messages: Vec<BasicReturnMessage>,
    dropped_confirms: Vec<PinkySwear<Confirmation>>,
    pinkies: VecDeque<PinkyBroadcaster<Confirmation>>,
}

impl Inner {
    fn register_pinky(&mut self, pinky: PinkyBroadcaster<Confirmation>) {
        if let Some(message) = self.waiting_messages.pop_front() {
            pinky.swear(Confirmation::Nack(message));
        } else {
            self.pinkies.push_back(pinky);
        }
    }

    fn register_dropped_confirm(&mut self, promise: PinkySwear<Confirmation>) {
        if let Some(confirmation) = promise.try_wait() {
            if let Confirmation::Nack(message) = confirmation {
                self.messages.push(message);
            }
        } else {
            self.dropped_confirms.push(promise);
        }
    }

    fn new_delivery_complete(&mut self) {
        if let Some(message) = self.current_message.take() {
            error!("Server returned us a message: {:?}", message);
            if let Some(pinky) = self.pinkies.pop_front() {
                pinky.swear(Confirmation::Nack(message));
            } else {
                self.waiting_messages.push_back(message);
            }
        }
    }

    fn drain(&mut self) -> Vec<BasicReturnMessage> {
        let mut messages = self.messages.drain(..).collect::<Vec<BasicReturnMessage>>();
        for promise in self
            .dropped_confirms
            .drain(..)
            .collect::<Vec<PinkySwear<Confirmation>>>()
        {
            if let Some(confirmation) = promise.try_wait() {
                if let Confirmation::Nack(message) = confirmation {
                    messages.push(message);
                }
            } else {
                self.dropped_confirms.push(promise);
            }
        }
        messages
    }
}
<|endoftext|>


<commit_before>use crate::command_prelude::*;

use cargo::core::{GitReference, SourceId};
use cargo::ops;
use cargo::util::IntoUrl;

pub fn cli() -> App {
    subcommand("install")
        .about("Install a Rust binary. Default location is $HOME/.cargo/bin")
        .arg_quiet()
        .arg(Arg::new("crate").empty_values(false).multiple(true))
        .arg(
            opt("version", "Specify a version to install")
                .alias("vers")
                .value_name("VERSION")
                .requires("crate"),
        )
        .arg(
            opt("git", "Git URL to install the specified crate from")
                .value_name("URL")
                .conflicts_with_all(&["path", "index", "registry"]),
        )
        .arg(
            opt("branch", "Branch to use when installing from git")
                .value_name("BRANCH")
                .requires("git"),
        )
        .arg(
            opt("tag", "Tag to use when installing from git")
                .value_name("TAG")
                .requires("git"),
        )
        .arg(
            opt("rev", "Specific commit to use when installing from git")
                .value_name("SHA")
                .requires("git"),
        )
        .arg(
            opt("path", "Filesystem path to local crate to install")
                .value_name("PATH")
                .conflicts_with_all(&["git", "index", "registry"]),
        )
        .arg(opt(
            "list",
            "list all installed packages and their versions",
        ))
        .arg_jobs()
        .arg(opt("force", "Force overwriting existing crates or binaries").short('f'))
        .arg(opt("no-track", "Do not save tracking information"))
        .arg_features()
        .arg_profile("Install artifacts with the specified profile")
        .arg(opt("debug", "Build in debug mode instead of release mode"))
        .arg_targets_bins_examples(
            "Install only the specified binary",
            "Install all binaries",
            "Install only the specified example",
            "Install all examples",
        )
        .arg_target_triple("Build for the target triple")
        .arg_target_dir()
        .arg(opt("root", "Directory to install packages into").value_name("DIR"))
        .arg(
            opt("index", "Registry index to install from")
                .value_name("INDEX")
                .requires("crate")
                .conflicts_with_all(&["git", "path", "registry"]),
        )
        .arg(
            opt("registry", "Registry to use")
                .value_name("REGISTRY")
                .requires("crate")
                .conflicts_with_all(&["git", "path", "index"]),
        )
        .arg_message_format()
        .after_help("Run `cargo help install` for more detailed information.\n")
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    if let Some(path) = args.value_of_path("path", config) {
        config.reload_rooted_at(path)?;
    } else {
        // TODO: Consider calling set_search_stop_path(home).
        config.reload_rooted_at(config.home().clone().into_path_unlocked())?;
    }

    let krates = args
        .values_of("crate")
        .unwrap_or_default()
        .collect::<Vec<_>>();

    let mut from_cwd = false;

    let source = if let Some(url) = args.value_of("git") {
        let url = url.into_url()?;
        let gitref = if let Some(branch) = args.value_of("branch") {
            GitReference::Branch(branch.to_string())
        } else if let Some(tag) = args.value_of("tag") {
            GitReference::Tag(tag.to_string())
        } else if let Some(rev) = args.value_of("rev") {
            GitReference::Rev(rev.to_string())
        } else {
            GitReference::DefaultBranch
        };
        SourceId::for_git(&url, gitref)?
    } else if let Some(path) = args.value_of_path("path", config) {
        SourceId::for_path(&path)?
    } else if krates.is_empty() {
        from_cwd = true;
        SourceId::for_path(config.cwd())?
    } else if let Some(registry) = args.registry(config)? {
        SourceId::alt_registry(config, &registry)?
    } else if let Some(index) = args.value_of("index") {
        SourceId::for_registry(&index.into_url()?)?
    } else {
        SourceId::crates_io(config)?
    };

    let version = args.value_of("version");
    let root = args.value_of("root");

    // We only provide workspace information for local crate installation from
    // one of the following sources:
    // - From current working directory (only work for edition 2015).
    // - From a specific local file path.
    let workspace = if from_cwd || args.is_present("path") {
        args.workspace(config).ok()
    } else {
        None
    };

    let mut compile_opts = args.compile_options(
        config,
        CompileMode::Build,
        workspace.as_ref(),
        ProfileChecking::Custom,
    )?;

    compile_opts.build_config.requested_profile =
        args.get_profile_name(config, "release", ProfileChecking::Custom)?;

    if args.is_present("list") {
        ops::install_list(root, config)?;
    } else {
        ops::install(
            config,
            root,
            krates,
            source,
            from_cwd,
            version,
            &compile_opts,
            args.is_present("force"),
            args.is_present("no-track"),
        )?;
    }
    Ok(())
}
<commit_msg>refactor: Resolve Arg::empty_values deprecation<commit_after>use crate::command_prelude::*;

use cargo::core::{GitReference, SourceId};
use cargo::ops;
use cargo::util::IntoUrl;

pub fn cli() -> App {
    subcommand("install")
        .about("Install a Rust binary. Default location is $HOME/.cargo/bin")
        .arg_quiet()
        .arg(Arg::new("crate").forbid_empty_values(true).multiple(true))
        .arg(
            opt("version", "Specify a version to install")
                .alias("vers")
                .value_name("VERSION")
                .requires("crate"),
        )
        .arg(
            opt("git", "Git URL to install the specified crate from")
                .value_name("URL")
                .conflicts_with_all(&["path", "index", "registry"]),
        )
        .arg(
            opt("branch", "Branch to use when installing from git")
                .value_name("BRANCH")
                .requires("git"),
        )
        .arg(
            opt("tag", "Tag to use when installing from git")
                .value_name("TAG")
                .requires("git"),
        )
        .arg(
            opt("rev", "Specific commit to use when installing from git")
                .value_name("SHA")
                .requires("git"),
        )
        .arg(
            opt("path", "Filesystem path to local crate to install")
                .value_name("PATH")
                .conflicts_with_all(&["git", "index", "registry"]),
        )
        .arg(opt(
            "list",
            "list all installed packages and their versions",
        ))
        .arg_jobs()
        .arg(opt("force", "Force overwriting existing crates or binaries").short('f'))
        .arg(opt("no-track", "Do not save tracking information"))
        .arg_features()
        .arg_profile("Install artifacts with the specified profile")
        .arg(opt("debug", "Build in debug mode instead of release mode"))
        .arg_targets_bins_examples(
            "Install only the specified binary",
            "Install all binaries",
            "Install only the specified example",
            "Install all examples",
        )
        .arg_target_triple("Build for the target triple")
        .arg_target_dir()
        .arg(opt("root", "Directory to install packages into").value_name("DIR"))
        .arg(
            opt("index", "Registry index to install from")
                .value_name("INDEX")
                .requires("crate")
                .conflicts_with_all(&["git", "path", "registry"]),
        )
        .arg(
            opt("registry", "Registry to use")
                .value_name("REGISTRY")
                .requires("crate")
                .conflicts_with_all(&["git", "path", "index"]),
        )
        .arg_message_format()
        .after_help("Run `cargo help install` for more detailed information.\n")
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    if let Some(path) = args.value_of_path("path", config) {
        config.reload_rooted_at(path)?;
    } else {
        // TODO: Consider calling set_search_stop_path(home).
        config.reload_rooted_at(config.home().clone().into_path_unlocked())?;
    }

    let krates = args
        .values_of("crate")
        .unwrap_or_default()
        .collect::<Vec<_>>();

    let mut from_cwd = false;

    let source = if let Some(url) = args.value_of("git") {
        let url = url.into_url()?;
        let gitref = if let Some(branch) = args.value_of("branch") {
            GitReference::Branch(branch.to_string())
        } else if let Some(tag) = args.value_of("tag") {
            GitReference::Tag(tag.to_string())
        } else if let Some(rev) = args.value_of("rev") {
            GitReference::Rev(rev.to_string())
        } else {
            GitReference::DefaultBranch
        };
        SourceId::for_git(&url, gitref)?
    } else if let Some(path) = args.value_of_path("path", config) {
        SourceId::for_path(&path)?
    } else if krates.is_empty() {
        from_cwd = true;
        SourceId::for_path(config.cwd())?
    } else if let Some(registry) = args.registry(config)? {
        SourceId::alt_registry(config, &registry)?
    } else if let Some(index) = args.value_of("index") {
        SourceId::for_registry(&index.into_url()?)?
    } else {
        SourceId::crates_io(config)?
    };

    let version = args.value_of("version");
    let root = args.value_of("root");

    // We only provide workspace information for local crate installation from
    // one of the following sources:
    // - From current working directory (only work for edition 2015).
    // - From a specific local file path.
    let workspace = if from_cwd || args.is_present("path") {
        args.workspace(config).ok()
    } else {
        None
    };

    let mut compile_opts = args.compile_options(
        config,
        CompileMode::Build,
        workspace.as_ref(),
        ProfileChecking::Custom,
    )?;

    compile_opts.build_config.requested_profile =
        args.get_profile_name(config, "release", ProfileChecking::Custom)?;

    if args.is_present("list") {
        ops::install_list(root, config)?;
    } else {
        ops::install(
            config,
            root,
            krates,
            source,
            from_cwd,
            version,
            &compile_opts,
            args.is_present("force"),
            args.is_present("no-track"),
        )?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>//! Just a dumping ground for cli stuff

use rustup::{self, Cfg, Notification, Toolchain, UpdateStatus};
use rustup::telemetry_analysis::TelemetryAnalysis;
use errors::*;
use rustup_utils::utils;
use rustup_utils::notify::NotificationLevel;
use self_update;
use std::io::{Write, BufRead, BufReader};
use std::process::{Command, Stdio};
use std::path::Path;
use std::{cmp, iter};
use std::sync::Arc;
use std::time::Duration;
use std;
use term2;
use wait_timeout::ChildExt;

pub fn confirm(question: &str, default: bool) -> Result<bool> {
    print!("{} ", question);
    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    let r = match &*input {
        "y" | "Y" => true,
        "n" | "N" => false,
        "" => default,
        _ => false,
    };

    println!("");

    Ok(r)
}

pub enum Confirm {
    Yes, No, Advanced
}

pub fn confirm_advanced() -> Result<Confirm> {
    println!("");
    println!("1) Proceed with installation (default)");
    println!("2) Customize installation");
    println!("3) Cancel installation");

    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    let r = match &*input {
        "1"|"" => Confirm::Yes,
        "2" => Confirm::Advanced,
        _ => Confirm::No,
    };

    println!("");

    Ok(r)
}

pub fn question_str(question: &str, default: &str) -> Result<String> {
    println!("{}", question);
    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    println!("");

    if input.is_empty() {
        Ok(default.to_string())
    } else {
        Ok(input)
    }
}

pub fn question_bool(question: &str, default: bool) -> Result<bool> {
    println!("{}", question);

    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    println!("");

    if input.is_empty() {
        Ok(default)
    } else {
        match &*input {
            "y" | "Y" | "yes" => Ok(true),
            "n" | "N" | "no" => Ok(false),
            _ => Ok(default)
        }
    }

}

pub fn read_line() -> Result<String> {
    let stdin = std::io::stdin();
    let stdin = stdin.lock();
    let mut lines = stdin.lines();
    lines.next().and_then(|l| l.ok()).ok_or(
        "unable to read from stdin for confirmation".into())
}

pub fn set_globals(verbose: bool) -> Result<Cfg> {
    use download_tracker::DownloadTracker;
    use std::cell::RefCell;

    let download_tracker = RefCell::new(DownloadTracker::new());

    Ok(try!(Cfg::from_env(Arc::new(move |n: Notification| {
       if download_tracker.borrow_mut().handle_notification(&n) {
            return;
        }

        match n.level() {
            NotificationLevel::Verbose => {
                if verbose {
                    verbose!("{}", n);
                }
            }
            NotificationLevel::Info => {
                info!("{}", n);
            }
            NotificationLevel::Warn => {
                warn!("{}", n);
            }
            NotificationLevel::Error => {
                err!("{}", n);
            }
        }
    }))))

}

pub fn show_channel_update(cfg: &Cfg, name: &str,
                           updated: rustup::Result<UpdateStatus>) -> Result<()> {
    show_channel_updates(cfg, vec![(name.to_string(), updated)])
}

fn show_channel_updates(cfg: &Cfg, toolchains: Vec<(String, rustup::Result<UpdateStatus>)>) -> Result<()> {
    let data = toolchains.into_iter().map(|(name, result)| {
        let ref toolchain = cfg.get_toolchain(&name, false).expect("");
        let version = rustc_version(toolchain);

        let banner;
        let color;
        match result {
            Ok(UpdateStatus::Installed) => {
                banner = "installed";
                color = Some(term2::color::BRIGHT_GREEN);
            }
            Ok(UpdateStatus::Updated) => {
                banner = "updated";
                color = Some(term2::color::BRIGHT_GREEN);
            }
            Ok(UpdateStatus::Unchanged) => {
                banner = "unchanged";
                color = None;
            }
            Err(_) => {
                banner = "update failed";
                color = Some(term2::color::BRIGHT_RED);
            }
        }

        let width = name.len() + 1 + banner.len();

        (name, banner, width, color, version)
    });

    let mut t = term2::stdout();

    let data: Vec<_> = data.collect();
    let max_width = data.iter().fold(0, |a, &(_, _, width, _, _)| cmp::max(a, width));

    for (name, banner, width, color, version) in data {
        let padding = max_width - width;
        let padding: String = iter::repeat(' ').take(padding).collect();
        let _ = write!(t, "  {}", padding);
        let _ = t.attr(term2::Attr::Bold);
        if let Some(color) = color {
            let _ = t.fg(color);
        }
        let _ = write!(t, "{} ", name);
        let _ = write!(t, "{}", banner);
        let _ = t.reset();
        let _ = writeln!(t, " - {}", version);
    }
    let _ = writeln!(t, "");

    Ok(())
}

pub fn update_all_channels(cfg: &Cfg, self_update: bool) -> Result<()> {

    let toolchains = try!(cfg.update_all_channels());

    if toolchains.is_empty() {
        info!("no updatable toolchains installed");
    }

    let setup_path = if self_update {
        try!(self_update::prepare_update())
    } else {
        None
    };

    if !toolchains.is_empty() {
        println!("");

        try!(show_channel_updates(cfg, toolchains));
    }

    if let Some(ref setup_path) = setup_path {
        try!(self_update::run_update(setup_path));

        unreachable!(); // update exits on success
    }

    Ok(())
}

pub fn rustc_version(toolchain: &Toolchain) -> String {
    if toolchain.exists() {
        let rustc_path = toolchain.binary_file("rustc");
        if utils::is_file(&rustc_path) {
            let mut cmd = Command::new(&rustc_path);
            cmd.arg("--version");
            cmd.stdin(Stdio::null());
            cmd.stdout(Stdio::piped());
            cmd.stderr(Stdio::piped());
            toolchain.set_ldpath(&mut cmd);

            // some toolchains are faulty with some combinations of platforms and
            // may fail to launch but also to timely terminate.
            // (known cases include Rust 1.3.0 through 1.10.0 in recent macOS Sierra.)
            // we guard against such cases by enforcing a reasonable timeout to read.
            let mut line1 = None;
            if let Ok(mut child) = cmd.spawn() {
                let timeout = Duration::new(1, 0);
                match child.wait_timeout(timeout) {
                    Ok(Some(status)) if status.success() => {
                        let out = child.stdout.expect("Child::stdout requested but not present");
                        let mut line = String::new();
                        if BufReader::new(out).read_line(&mut line).is_ok() {
                            let lineend = line.trim_right_matches(&['\r', '\n'][..]).len();
                            line.truncate(lineend);
                            line1 = Some(line);
                        }
                    }
                    Ok(None) => {
                        let _ = child.kill();
                    }
                    Ok(Some(_)) | Err(_) => {}
                }
            }

            if let Some(line1) = line1 {
                line1.to_owned()
            } else {
                String::from("(error reading rustc version)")
            }
        } else {
            String::from("(rustc does not exist)")
        }
    } else {
        String::from("(toolchain not installed)")
    }
}

pub fn list_targets(toolchain: &Toolchain) -> Result<()> {
    let mut t = term2::stdout();
    for component in try!(toolchain.list_components()) {
        if component.component.pkg == "rust-std" {
            let target = component.component.target.as_ref().expect("rust-std should have a target");
            if component.required {
                let _ = t.attr(term2::Attr::Bold);
                let _ = writeln!(t, "{} (default)", target);
                let _ = t.reset();
            } else if component.installed {
                let _ = t.attr(term2::Attr::Bold);
                let _ = writeln!(t, "{} (installed)", target);
                let _ = t.reset();
            } else if component.available {
                let _ = writeln!(t, "{}", target);
            }
        }
    }

    Ok(())
}

pub fn list_components(toolchain: &Toolchain) -> Result<()> {
    let mut t = term2::stdout();
    for component in try!(toolchain.list_components()) {
        let name = component.component.name();
        if component.required {
            let _ = t.attr(term2::Attr::Bold);
            let _ = writeln!(t, "{} (default)", name);
            let _ = t.reset();
        } else if component.installed {
            let _ = t.attr(term2::Attr::Bold);
            let _ = writeln!(t, "{} (installed)", name);
            let _ = t.reset();
        } else if component.available {
            let _ = writeln!(t, "{}", name);
        }
    }

    Ok(())
}

pub fn list_toolchains(cfg: &Cfg) -> Result<()> {
    let toolchains = try!(cfg.list_toolchains());

    if toolchains.is_empty() {
        println!("no installed toolchains");
    } else {
        if let Ok(Some(def_toolchain)) = cfg.find_default() {
            for toolchain in toolchains {
                let if_default = if def_toolchain.name() == &*toolchain {
                    " (default)"
                } else {
                    ""
                };
                println!("{}{}", &toolchain, if_default);
            }

        } else {
            for toolchain in toolchains {
                println!("{}", &toolchain);
            }
        }
    }
    Ok(())
}

pub fn list_overrides(cfg: &Cfg) -> Result<()> {
    let overrides = try!(cfg.settings_file.with(|s| Ok(s.overrides.clone())));

    if overrides.is_empty() {
        println!("no overrides");
    } else {
        let mut any_not_exist = false;
        for (k, v) in overrides {
            let dir_exists = Path::new(&k).is_dir();
            if !dir_exists {
                any_not_exist = true;
            }
            println!("{:<40}\t{:<20}",
                     utils::format_path_for_display(&k) +
                     if dir_exists {
                         ""
                     } else {
                         " (not a directory)"
                     },
                     v)
        }
        if any_not_exist {
            println!("");
            info!("you may remove overrides for non-existent directories with
`rustup override unset --nonexistent`");
        }
    }
    Ok(())
}

pub fn version() -> &'static str {
    concat!(env!("CARGO_PKG_VERSION"), include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt")))
}

pub fn report_error(e: &Error) {
    err!("{}", e);

    for e in e.iter().skip(1) {
        info!("caused by: {}", e);
    }

    if show_backtrace() {
        if let Some(backtrace) = e.backtrace() {
            info!("backtrace:");
            println!("");
            println!("{:?}", backtrace);
        }
    } else {
    }

    fn show_backtrace() -> bool {
        use std::env;
        use std::ops::Deref;

        if env::var("RUST_BACKTRACE").as_ref().map(Deref::deref) == Ok("1") {
            return true;
        }

        for arg in env::args() {
            if arg == "-v" || arg == "--verbose" {
                return true;
            }
        }

        false
    }
}

pub fn show_telemetry(analysis: TelemetryAnalysis) -> Result<()> {
    println!("Telemetry Analysis");

    println!("{}", analysis);

    Ok(())
}
<commit_msg>Increase Rust detection timeout to 3 seconds<commit_after>//! Just a dumping ground for cli stuff

use rustup::{self, Cfg, Notification, Toolchain, UpdateStatus};
use rustup::telemetry_analysis::TelemetryAnalysis;
use errors::*;
use rustup_utils::utils;
use rustup_utils::notify::NotificationLevel;
use self_update;
use std::io::{Write, BufRead, BufReader};
use std::process::{Command, Stdio};
use std::path::Path;
use std::{cmp, iter};
use std::sync::Arc;
use std::time::Duration;
use std;
use term2;
use wait_timeout::ChildExt;

pub fn confirm(question: &str, default: bool) -> Result<bool> {
    print!("{} ", question);
    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    let r = match &*input {
        "y" | "Y" => true,
        "n" | "N" => false,
        "" => default,
        _ => false,
    };

    println!("");

    Ok(r)
}

pub enum Confirm {
    Yes, No, Advanced
}

pub fn confirm_advanced() -> Result<Confirm> {
    println!("");
    println!("1) Proceed with installation (default)");
    println!("2) Customize installation");
    println!("3) Cancel installation");

    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    let r = match &*input {
        "1"|"" => Confirm::Yes,
        "2" => Confirm::Advanced,
        _ => Confirm::No,
    };

    println!("");

    Ok(r)
}

pub fn question_str(question: &str, default: &str) -> Result<String> {
    println!("{}", question);
    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    println!("");

    if input.is_empty() {
        Ok(default.to_string())
    } else {
        Ok(input)
    }
}

pub fn question_bool(question: &str, default: bool) -> Result<bool> {
    println!("{}", question);

    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    println!("");

    if input.is_empty() {
        Ok(default)
    } else {
        match &*input {
            "y" | "Y" | "yes" => Ok(true),
            "n" | "N" | "no" => Ok(false),
            _ => Ok(default)
        }
    }

}

pub fn read_line() -> Result<String> {
    let stdin = std::io::stdin();
    let stdin = stdin.lock();
    let mut lines = stdin.lines();
    lines.next().and_then(|l| l.ok()).ok_or(
        "unable to read from stdin for confirmation".into())
}

pub fn set_globals(verbose: bool) -> Result<Cfg> {
    use download_tracker::DownloadTracker;
    use std::cell::RefCell;

    let download_tracker = RefCell::new(DownloadTracker::new());

    Ok(try!(Cfg::from_env(Arc::new(move |n: Notification| {
       if download_tracker.borrow_mut().handle_notification(&n) {
            return;
        }

        match n.level() {
            NotificationLevel::Verbose => {
                if verbose {
                    verbose!("{}", n);
                }
            }
            NotificationLevel::Info => {
                info!("{}", n);
            }
            NotificationLevel::Warn => {
                warn!("{}", n);
            }
            NotificationLevel::Error => {
                err!("{}", n);
            }
        }
    }))))

}

pub fn show_channel_update(cfg: &Cfg, name: &str,
                           updated: rustup::Result<UpdateStatus>) -> Result<()> {
    show_channel_updates(cfg, vec![(name.to_string(), updated)])
}

fn show_channel_updates(cfg: &Cfg, toolchains: Vec<(String, rustup::Result<UpdateStatus>)>) -> Result<()> {
    let data = toolchains.into_iter().map(|(name, result)| {
        let ref toolchain = cfg.get_toolchain(&name, false).expect("");
        let version = rustc_version(toolchain);

        let banner;
        let color;
        match result {
            Ok(UpdateStatus::Installed) => {
                banner = "installed";
                color = Some(term2::color::BRIGHT_GREEN);
            }
            Ok(UpdateStatus::Updated) => {
                banner = "updated";
                color = Some(term2::color::BRIGHT_GREEN);
            }
            Ok(UpdateStatus::Unchanged) => {
                banner = "unchanged";
                color = None;
            }
            Err(_) => {
                banner = "update failed";
                color = Some(term2::color::BRIGHT_RED);
            }
        }

        let width = name.len() + 1 + banner.len();

        (name, banner, width, color, version)
    });

    let mut t = term2::stdout();

    let data: Vec<_> = data.collect();
    let max_width = data.iter().fold(0, |a, &(_, _, width, _, _)| cmp::max(a, width));

    for (name, banner, width, color, version) in data {
        let padding = max_width - width;
        let padding: String = iter::repeat(' ').take(padding).collect();
        let _ = write!(t, "  {}", padding);
        let _ = t.attr(term2::Attr::Bold);
        if let Some(color) = color {
            let _ = t.fg(color);
        }
        let _ = write!(t, "{} ", name);
        let _ = write!(t, "{}", banner);
        let _ = t.reset();
        let _ = writeln!(t, " - {}", version);
    }
    let _ = writeln!(t, "");

    Ok(())
}

pub fn update_all_channels(cfg: &Cfg, self_update: bool) -> Result<()> {

    let toolchains = try!(cfg.update_all_channels());

    if toolchains.is_empty() {
        info!("no updatable toolchains installed");
    }

    let setup_path = if self_update {
        try!(self_update::prepare_update())
    } else {
        None
    };

    if !toolchains.is_empty() {
        println!("");

        try!(show_channel_updates(cfg, toolchains));
    }

    if let Some(ref setup_path) = setup_path {
        try!(self_update::run_update(setup_path));

        unreachable!(); // update exits on success
    }

    Ok(())
}

pub fn rustc_version(toolchain: &Toolchain) -> String {
    if toolchain.exists() {
        let rustc_path = toolchain.binary_file("rustc");
        if utils::is_file(&rustc_path) {
            let mut cmd = Command::new(&rustc_path);
            cmd.arg("--version");
            cmd.stdin(Stdio::null());
            cmd.stdout(Stdio::piped());
            cmd.stderr(Stdio::piped());
            toolchain.set_ldpath(&mut cmd);

            // some toolchains are faulty with some combinations of platforms and
            // may fail to launch but also to timely terminate.
            // (known cases include Rust 1.3.0 through 1.10.0 in recent macOS Sierra.)
            // we guard against such cases by enforcing a reasonable timeout to read.
            let mut line1 = None;
            if let Ok(mut child) = cmd.spawn() {
                let timeout = Duration::new(3, 0);
                match child.wait_timeout(timeout) {
                    Ok(Some(status)) if status.success() => {
                        let out = child.stdout.expect("Child::stdout requested but not present");
                        let mut line = String::new();
                        if BufReader::new(out).read_line(&mut line).is_ok() {
                            let lineend = line.trim_right_matches(&['\r', '\n'][..]).len();
                            line.truncate(lineend);
                            line1 = Some(line);
                        }
                    }
                    Ok(None) => {
                        let _ = child.kill();
                    }
                    Ok(Some(_)) | Err(_) => {}
                }
            }

            if let Some(line1) = line1 {
                line1.to_owned()
            } else {
                String::from("(error reading rustc version)")
            }
        } else {
            String::from("(rustc does not exist)")
        }
    } else {
        String::from("(toolchain not installed)")
    }
}

pub fn list_targets(toolchain: &Toolchain) -> Result<()> {
    let mut t = term2::stdout();
    for component in try!(toolchain.list_components()) {
        if component.component.pkg == "rust-std" {
            let target = component.component.target.as_ref().expect("rust-std should have a target");
            if component.required {
                let _ = t.attr(term2::Attr::Bold);
                let _ = writeln!(t, "{} (default)", target);
                let _ = t.reset();
            } else if component.installed {
                let _ = t.attr(term2::Attr::Bold);
                let _ = writeln!(t, "{} (installed)", target);
                let _ = t.reset();
            } else if component.available {
                let _ = writeln!(t, "{}", target);
            }
        }
    }

    Ok(())
}

pub fn list_components(toolchain: &Toolchain) -> Result<()> {
    let mut t = term2::stdout();
    for component in try!(toolchain.list_components()) {
        let name = component.component.name();
        if component.required {
            let _ = t.attr(term2::Attr::Bold);
            let _ = writeln!(t, "{} (default)", name);
            let _ = t.reset();
        } else if component.installed {
            let _ = t.attr(term2::Attr::Bold);
            let _ = writeln!(t, "{} (installed)", name);
            let _ = t.reset();
        } else if component.available {
            let _ = writeln!(t, "{}", name);
        }
    }

    Ok(())
}

pub fn list_toolchains(cfg: &Cfg) -> Result<()> {
    let toolchains = try!(cfg.list_toolchains());

    if toolchains.is_empty() {
        println!("no installed toolchains");
    } else {
        if let Ok(Some(def_toolchain)) = cfg.find_default() {
            for toolchain in toolchains {
                let if_default = if def_toolchain.name() == &*toolchain {
                    " (default)"
                } else {
                    ""
                };
                println!("{}{}", &toolchain, if_default);
            }

        } else {
            for toolchain in toolchains {
                println!("{}", &toolchain);
            }
        }
    }
    Ok(())
}

pub fn list_overrides(cfg: &Cfg) -> Result<()> {
    let overrides = try!(cfg.settings_file.with(|s| Ok(s.overrides.clone())));

    if overrides.is_empty() {
        println!("no overrides");
    } else {
        let mut any_not_exist = false;
        for (k, v) in overrides {
            let dir_exists = Path::new(&k).is_dir();
            if !dir_exists {
                any_not_exist = true;
            }
            println!("{:<40}\t{:<20}",
                     utils::format_path_for_display(&k) +
                     if dir_exists {
                         ""
                     } else {
                         " (not a directory)"
                     },
                     v)
        }
        if any_not_exist {
            println!("");
            info!("you may remove overrides for non-existent directories with
`rustup override unset --nonexistent`");
        }
    }
    Ok(())
}

pub fn version() -> &'static str {
    concat!(env!("CARGO_PKG_VERSION"), include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt")))
}

pub fn report_error(e: &Error) {
    err!("{}", e);

    for e in e.iter().skip(1) {
        info!("caused by: {}", e);
    }

    if show_backtrace() {
        if let Some(backtrace) = e.backtrace() {
            info!("backtrace:");
            println!("");
            println!("{:?}", backtrace);
        }
    } else {
    }

    fn show_backtrace() -> bool {
        use std::env;
        use std::ops::Deref;

        if env::var("RUST_BACKTRACE").as_ref().map(Deref::deref) == Ok("1") {
            return true;
        }

        for arg in env::args() {
            if arg == "-v" || arg == "--verbose" {
                return true;
            }
        }

        false
    }
}

pub fn show_telemetry(analysis: TelemetryAnalysis) -> Result<()> {
    println!("Telemetry Analysis");

    println!("{}", analysis);

    Ok(())
}
<|endoftext|>


<commit_before>use std::fmt::{self, Debug};
use std::marker::PhantomData;

/// Build configuration. See [CFG].
pub struct Cfg<'a> {
    pub include_prefix: &'a str,
    marker: PhantomData<*const ()>, // !Send + !Sync
}

/// Global configuration of the current build.
///
///

///
/// ## **`CFG.include_prefix`**
///
/// Presently the only exposed configuration is the `include_prefix`, the prefix
/// at which C++ code from your crate as well as directly dependent crates can
/// access the code generated during this build.
///
/// By default, the `include_prefix` is equal to the name of the current crate.
/// That means if our crate is called `demo` and has Rust source files in a
/// *src/* directory and maybe some handwritten C++ header files in an
/// *include/* directory, then the current crate as well as downstream crates
/// might include them as follows:
///
/// ```
/// # const _: &str = stringify! {
///   // include one of the handwritten headers:
/// #include "demo/include/wow.h"
///
///   // include a header generated from Rust cxx::bridge:
/// #include "demo/src/lib.rs.h"
/// # };
/// ```
///
/// By modifying `CFG.include_prefix` we can substitute a prefix that is
/// different from the crate name if desired. Here we'll change it to
/// `"path/to"` which will make import paths take the form
/// `"path/to/include/wow.h"` and `"path/to/src/lib.rs.h"`.
///
/// ```no_run
/// // build.rs
///
/// use cxx_build::CFG;
///
/// fn main() {
///     CFG.include_prefix = "path/to";
///
///     cxx_build::bridge("src/lib.rs")
///         .file("src/demo.cc") // probably contains `#include "path/to/src/lib.rs.h"`
///         /* ... */
///         .compile("demo");
/// }
/// ```
///
/// Note that cross-crate imports are only made available between **direct
/// dependencies**. Another crate must directly depend on your crate in order to
/// #include its headers; a transitive dependency is not sufficient.
/// Additionally, headers from a direct dependency are only importable if the
/// dependency's Cargo.toml manifest contains a `links` key. If not, its headers
/// will not be importable from outside of the same crate.
#[cfg(doc)]
pub static mut CFG: Cfg = Cfg {
    include_prefix: "",
    marker: PhantomData,
};

impl<'a> Debug for Cfg<'a> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter
            .debug_struct("Cfg")
            .field("include_prefix", &self.include_prefix)
            .finish()
    }
}

#[cfg(not(doc))]
pub use self::r#impl::Cfg::CFG;

#[cfg(not(doc))]
mod r#impl {
    use lazy_static::lazy_static;
    use std::cell::RefCell;
    use std::collections::HashMap;
    use std::fmt::{self, Debug};
    use std::marker::PhantomData;
    use std::ops::{Deref, DerefMut};
    use std::sync::{PoisonError, RwLock};

    lazy_static! {
        static ref PACKAGE_NAME: Box<str> = {
            crate::env_os("CARGO_PKG_NAME")
                .map(|pkg| pkg.to_string_lossy().into_owned().into_boxed_str())
                .unwrap_or_default()
        };
        static ref INCLUDE_PREFIX: RwLock<Vec<&'static str>> = RwLock::new(vec![&PACKAGE_NAME]);
    }

    thread_local! {
        static CONST_DEREFS: RefCell<HashMap<Handle, Box<super::Cfg<'static>>>> = RefCell::default();
    }

    #[derive(Eq, PartialEq, Hash)]
    struct Handle(*const Cfg<'static>);

    impl<'a> Cfg<'a> {
        fn current() -> super::Cfg<'a> {
            let include_prefix = *INCLUDE_PREFIX
                .read()
                .unwrap_or_else(PoisonError::into_inner)
                .last()
                .unwrap();
            super::Cfg {
                include_prefix,
                marker: PhantomData,
            }
        }

        const fn handle(self: &Cfg<'a>) -> Handle {
            Handle(<*const Cfg>::cast(self))
        }
    }

    // Since super::Cfg is !Send and !Sync, all Cfg are thread local and will
    // drop on the same thread where they were created.
    pub enum Cfg<'a> {
        Mut(super::Cfg<'a>),
        CFG,
    }

    impl<'a> Debug for Cfg<'a> {
        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            if let Cfg::Mut(cfg) = self {
                Debug::fmt(cfg, formatter)
            } else {
                Debug::fmt(&Cfg::current(), formatter)
            }
        }
    }

    impl<'a> Deref for Cfg<'a> {
        type Target = super::Cfg<'a>;

        fn deref(&self) -> &Self::Target {
            if let Cfg::Mut(cfg) = self {
                cfg
            } else {
                let cfg = CONST_DEREFS.with(|derefs| -> *mut super::Cfg {
                    &mut **derefs
                        .borrow_mut()
                        .entry(self.handle())
                        .or_insert_with(|| Box::new(Cfg::current()))
                });
                unsafe { &mut *cfg }
            }
        }
    }

    impl<'a> DerefMut for Cfg<'a> {
        fn deref_mut(&mut self) -> &mut Self::Target {
            if let Cfg::CFG = self {
                CONST_DEREFS.with(|derefs| derefs.borrow_mut().remove(&self.handle()));
                *self = Cfg::Mut(Cfg::current());
            }
            match self {
                Cfg::Mut(cfg) => cfg,
                Cfg::CFG => unreachable!(),
            }
        }
    }

    impl<'a> Drop for Cfg<'a> {
        fn drop(&mut self) {
            if let Cfg::Mut(cfg) = self {
                INCLUDE_PREFIX
                    .write()
                    .unwrap_or_else(PoisonError::into_inner)
                    .push(Box::leak(Box::from(cfg.include_prefix)));
            } else {
                CONST_DEREFS.with(|derefs| derefs.borrow_mut().remove(&self.handle()));
            }
        }
    }
}
<commit_msg>Add fixme to remove const derefs side table<commit_after>use std::fmt::{self, Debug};
use std::marker::PhantomData;

/// Build configuration. See [CFG].
pub struct Cfg<'a> {
    pub include_prefix: &'a str,
    marker: PhantomData<*const ()>, // !Send + !Sync
}

/// Global configuration of the current build.
///
///

///
/// ## **`CFG.include_prefix`**
///
/// Presently the only exposed configuration is the `include_prefix`, the prefix
/// at which C++ code from your crate as well as directly dependent crates can
/// access the code generated during this build.
///
/// By default, the `include_prefix` is equal to the name of the current crate.
/// That means if our crate is called `demo` and has Rust source files in a
/// *src/* directory and maybe some handwritten C++ header files in an
/// *include/* directory, then the current crate as well as downstream crates
/// might include them as follows:
///
/// ```
/// # const _: &str = stringify! {
///   // include one of the handwritten headers:
/// #include "demo/include/wow.h"
///
///   // include a header generated from Rust cxx::bridge:
/// #include "demo/src/lib.rs.h"
/// # };
/// ```
///
/// By modifying `CFG.include_prefix` we can substitute a prefix that is
/// different from the crate name if desired. Here we'll change it to
/// `"path/to"` which will make import paths take the form
/// `"path/to/include/wow.h"` and `"path/to/src/lib.rs.h"`.
///
/// ```no_run
/// // build.rs
///
/// use cxx_build::CFG;
///
/// fn main() {
///     CFG.include_prefix = "path/to";
///
///     cxx_build::bridge("src/lib.rs")
///         .file("src/demo.cc") // probably contains `#include "path/to/src/lib.rs.h"`
///         /* ... */
///         .compile("demo");
/// }
/// ```
///
/// Note that cross-crate imports are only made available between **direct
/// dependencies**. Another crate must directly depend on your crate in order to
/// #include its headers; a transitive dependency is not sufficient.
/// Additionally, headers from a direct dependency are only importable if the
/// dependency's Cargo.toml manifest contains a `links` key. If not, its headers
/// will not be importable from outside of the same crate.
#[cfg(doc)]
pub static mut CFG: Cfg = Cfg {
    include_prefix: "",
    marker: PhantomData,
};

impl<'a> Debug for Cfg<'a> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter
            .debug_struct("Cfg")
            .field("include_prefix", &self.include_prefix)
            .finish()
    }
}

#[cfg(not(doc))]
pub use self::r#impl::Cfg::CFG;

#[cfg(not(doc))]
mod r#impl {
    use lazy_static::lazy_static;
    use std::cell::RefCell;
    use std::collections::HashMap;
    use std::fmt::{self, Debug};
    use std::marker::PhantomData;
    use std::ops::{Deref, DerefMut};
    use std::sync::{PoisonError, RwLock};

    lazy_static! {
        static ref PACKAGE_NAME: Box<str> = {
            crate::env_os("CARGO_PKG_NAME")
                .map(|pkg| pkg.to_string_lossy().into_owned().into_boxed_str())
                .unwrap_or_default()
        };
        static ref INCLUDE_PREFIX: RwLock<Vec<&'static str>> = RwLock::new(vec![&PACKAGE_NAME]);
    }

    thread_local! {
        // FIXME: If https://github.com/rust-lang/rust/issues/77425 is resolved,
        // we can delete this thread local side table and instead make each CFG
        // instance directly own the associated super::Cfg.
        //
        //     #[allow(const_item_mutation)]
        //     pub const CFG: Cfg = Cfg {
        //         cfg: AtomicPtr::new(ptr::null_mut()),
        //     };
        //     pub struct Cfg {
        //         cfg: AtomicPtr<super::Cfg>,
        //     }
        //
        static CONST_DEREFS: RefCell<HashMap<Handle, Box<super::Cfg<'static>>>> = RefCell::default();
    }

    #[derive(Eq, PartialEq, Hash)]
    struct Handle(*const Cfg<'static>);

    impl<'a> Cfg<'a> {
        fn current() -> super::Cfg<'a> {
            let include_prefix = *INCLUDE_PREFIX
                .read()
                .unwrap_or_else(PoisonError::into_inner)
                .last()
                .unwrap();
            super::Cfg {
                include_prefix,
                marker: PhantomData,
            }
        }

        const fn handle(self: &Cfg<'a>) -> Handle {
            Handle(<*const Cfg>::cast(self))
        }
    }

    // Since super::Cfg is !Send and !Sync, all Cfg are thread local and will
    // drop on the same thread where they were created.
    pub enum Cfg<'a> {
        Mut(super::Cfg<'a>),
        CFG,
    }

    impl<'a> Debug for Cfg<'a> {
        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            if let Cfg::Mut(cfg) = self {
                Debug::fmt(cfg, formatter)
            } else {
                Debug::fmt(&Cfg::current(), formatter)
            }
        }
    }

    impl<'a> Deref for Cfg<'a> {
        type Target = super::Cfg<'a>;

        fn deref(&self) -> &Self::Target {
            if let Cfg::Mut(cfg) = self {
                cfg
            } else {
                let cfg = CONST_DEREFS.with(|derefs| -> *mut super::Cfg {
                    &mut **derefs
                        .borrow_mut()
                        .entry(self.handle())
                        .or_insert_with(|| Box::new(Cfg::current()))
                });
                unsafe { &mut *cfg }
            }
        }
    }

    impl<'a> DerefMut for Cfg<'a> {
        fn deref_mut(&mut self) -> &mut Self::Target {
            if let Cfg::CFG = self {
                CONST_DEREFS.with(|derefs| derefs.borrow_mut().remove(&self.handle()));
                *self = Cfg::Mut(Cfg::current());
            }
            match self {
                Cfg::Mut(cfg) => cfg,
                Cfg::CFG => unreachable!(),
            }
        }
    }

    impl<'a> Drop for Cfg<'a> {
        fn drop(&mut self) {
            if let Cfg::Mut(cfg) = self {
                INCLUDE_PREFIX
                    .write()
                    .unwrap_or_else(PoisonError::into_inner)
                    .push(Box::leak(Box::from(cfg.include_prefix)));
            } else {
                CONST_DEREFS.with(|derefs| derefs.borrow_mut().remove(&self.handle()));
            }
        }
    }
}
<|endoftext|>


<commit_before>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended to be used from Cargo build scripts to execute CXX's
//! C++ code generator, set up any additional compiler flags depending on
//! the use case, and make the C++ compiler invocation.
//!
//!

//!
//! # Example
//!
//! Example of a canonical Cargo build script that builds a CXX bridge:
//!
//! ```no_run
//! // build.rs
//!
//! fn main() {
//!     cxx_build::bridge("src/main.rs")
//!         .file("src/demo.cc")
//!         .flag_if_supported("-std=c++11")
//!         .compile("cxxbridge-demo");
//!
//!     println!("cargo:rerun-if-changed=src/main.rs");
//!     println!("cargo:rerun-if-changed=src/demo.cc");
//!     println!("cargo:rerun-if-changed=include/demo.h");
//! }
//! ```
//!
//! A runnable working setup with this build script is shown in the *demo*
//! directory of [https://github.com/dtolnay/cxx].
//!
//! [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
//!
//!

//!
//! # Alternatives
//!
//! For use in non-Cargo builds like Bazel or Buck, CXX provides an
//! alternate way of invoking the C++ code generator as a standalone command
//! line tool. The tool is packaged as the `cxxbridge-cmd` crate.
//!
//! ```bash
//! $ cargo install cxxbridge-cmd  # or build it from the repo
//!
//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
//! ```

#![allow(
    clippy::inherent_to_string,
    clippy::needless_doctest_main,
    clippy::new_without_default,
    clippy::or_fun_call,
    clippy::toplevel_ref_arg
)]

mod cargo;
mod error;
mod gen;
mod out;
mod paths;
mod syntax;

use crate::error::{Error, Result};
use crate::gen::error::report;
use crate::gen::Opt;
use crate::paths::{PathExt, TargetDir};
use cc::Build;
use std::env;
use std::ffi::{OsStr, OsString};
use std::io::{self, Write};
use std::iter;
use std::path::{Path, PathBuf};
use std::process;

/// This returns a [`cc::Build`] on which you should continue to set up any
/// additional source files or compiler flags, and lastly call its [`compile`]
/// method to execute the C++ build.
///
/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
#[must_use]
pub fn bridge(rust_source_file: impl AsRef<Path>) -> Build {
    bridges(iter::once(rust_source_file))
}

/// `cxx_build::bridge` but for when more than one file contains a
/// #\[cxx::bridge\] module.
///
/// ```no_run
/// let source_files = vec!["src/main.rs", "src/path/to/other.rs"];
/// cxx_build::bridges(source_files)
///     .file("src/demo.cc")
///     .flag_if_supported("-std=c++11")
///     .compile("cxxbridge-demo");
/// ```
#[must_use]
pub fn bridges(rust_source_files: impl IntoIterator<Item = impl AsRef<Path>>) -> Build {
    let ref mut rust_source_files = rust_source_files.into_iter();
    build(rust_source_files).unwrap_or_else(|err| {
        let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {}\n\n", report(err));
        process::exit(1);
    })
}

struct Project {
    package_name: OsString,
    manifest_dir: PathBuf,
    // Output directory as received from Cargo.
    out_dir: PathBuf,
    // Directory into which to symlink all generated code.
    //
    // This is *not* used for an #include path, only as a debugging convenience.
    // Normally available at target/cxxbridge/ if we are able to know where the
    // target dir is, otherwise under a common scratch dir.
    //
    // The reason this isn't the #include dir is that we do not want builds to
    // have access to headers from arbitrary other parts of the dependency
    // graph. Using a global directory for all builds would be both a race
    // condition depending on what order Cargo randomly executes the build
    // scripts, as well as semantically undesirable for builds not to have to
    // declare their real dependencies.
    shared_dir: PathBuf,
}

impl Project {
    fn init() -> Result<Self> {
        let package_name = env_os("CARGO_PKG_NAME")?;
        let manifest_dir = paths::manifest_dir()?;
        let out_dir = paths::out_dir()?;

        let target_dir = match cargo::target_dir(&out_dir) {
            target_dir @ TargetDir::Path(_) => target_dir,
            // Fallback if Cargo did not work.
            TargetDir::Unknown => paths::search_parents_for_target_dir(&out_dir),
        };

        let shared_dir = match target_dir {
            TargetDir::Path(target_dir) => target_dir.join("cxxbridge"),
            // Use cxx-build's OUT_DIR.
            TargetDir::Unknown => PathBuf::from(env!("OUT_DIR")),
        };

        Ok(Project {
            package_name,
            manifest_dir,
            out_dir,
            shared_dir,
        })
    }
}

// We lay out the OUT_DIR as follows. Everything is namespaced under a cxxbridge
// subdirectory to avoid stomping on other things that the caller's build script
// might be doing inside OUT_DIR.
//
//     $OUT_DIR/
//        cxxbridge/
//           crate/
//              $CARGO_PKG_NAME -> $CARGO_MANIFEST_DIR
//           include/
//              rust/
//                 cxx.h
//              $CARGO_PKG_NAME/
//                 .../
//                    lib.rs.h
//           sources/
//              $CARGO_PKG_NAME/
//                 .../
//                    lib.rs.cc
//
// The crate/ and include/ directories are placed on the #include path.
fn build(rust_source_files: &mut dyn Iterator<Item = impl AsRef<Path>>) -> Result<Build> {
    let ref prj = Project::init()?;

    let ref crate_dir = make_crate_dir(prj);
    let ref include_dir = make_include_dir(prj)?;

    let mut build = Build::new();
    build.cpp(true);
    build.cpp_link_stdlib(None); // linked via link-cplusplus crate
    build.include(include_dir);
    if let Some(crate_dir) = crate_dir {
        // Placed after the generated code directory (include_dir) on the
        // include line so that `#include "path/to/file.rs"` from C++
        // "magically" works and refers to the API generated from that Rust
        // source file.
        build.include(crate_dir);
    }

    for path in rust_source_files {
        generate_bridge(prj, &mut build, path.as_ref())?;
    }

    eprintln!("\nCXX include path:");
    if let Some(crate_dir) = crate_dir {
        eprintln!("  {}", crate_dir.display());
    }
    eprintln!("  {}", include_dir.display());
    Ok(build)
}

fn make_crate_dir(prj: &Project) -> Option<PathBuf> {
    let crate_dir = prj.out_dir.join("cxxbridge").join("crate");
    let link = crate_dir.join(&prj.package_name);
    if out::symlink_dir(&prj.manifest_dir, link).is_ok() {
        Some(crate_dir)
    } else {
        None
    }
}

fn make_include_dir(prj: &Project) -> Result<PathBuf> {
    let include_dir = prj.out_dir.join("cxxbridge").join("include");
    let cxx_h = include_dir.join("rust").join("cxx.h");
    let ref shared_cxx_h = prj.shared_dir.join("rust").join("cxx.h");
    if let Some(ref original) = env::var_os("DEP_CXXBRIDGE04_HEADER") {
        out::symlink_file(original, cxx_h)?;
        out::symlink_file(original, shared_cxx_h)?;
    } else {
        out::write(shared_cxx_h, gen::include::HEADER.as_bytes())?;
        out::symlink_file(shared_cxx_h, cxx_h)?;
    }
    Ok(include_dir)
}

fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) -> Result<()> {
    let opt = Opt::default();
    let generated = gen::generate_from_path(rust_source_file, &opt);
    let ref rel_path = paths::local_relative_path(rust_source_file);

    let cxxbridge = prj.out_dir.join("cxxbridge");
    let include_dir = cxxbridge.join("include").join(&prj.package_name);
    let sources_dir = cxxbridge.join("sources").join(&prj.package_name);

    let ref rel_path_h = rel_path.with_appended_extension(".h");
    let ref header_path = include_dir.join(rel_path_h);
    out::write(header_path, &generated.header)?;

    let ref link_path = include_dir.join(rel_path);
    let _ = out::symlink_file(header_path, link_path);

    let ref rel_path_cc = rel_path.with_appended_extension(".cc");
    let ref implementation_path = sources_dir.join(rel_path_cc);
    out::write(implementation_path, &generated.implementation)?;
    build.file(implementation_path);

    let shared_h = prj.shared_dir.join(&prj.package_name).join(rel_path_h);
    let shared_cc = prj.shared_dir.join(&prj.package_name).join(rel_path_cc);
    let _ = out::symlink_file(header_path, shared_h);
    let _ = out::symlink_file(implementation_path, shared_cc);
    Ok(())
}

fn env_os(key: impl AsRef<OsStr>) -> Result<OsString> {
    let key = key.as_ref();
    env::var_os(key).ok_or_else(|| Error::NoEnv(key.to_owned()))
}
<commit_msg>Place direct dependencies on the include path<commit_after>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended to be used from Cargo build scripts to execute CXX's
//! C++ code generator, set up any additional compiler flags depending on
//! the use case, and make the C++ compiler invocation.
//!
//!

//!
//! # Example
//!
//! Example of a canonical Cargo build script that builds a CXX bridge:
//!
//! ```no_run
//! // build.rs
//!
//! fn main() {
//!     cxx_build::bridge("src/main.rs")
//!         .file("src/demo.cc")
//!         .flag_if_supported("-std=c++11")
//!         .compile("cxxbridge-demo");
//!
//!     println!("cargo:rerun-if-changed=src/main.rs");
//!     println!("cargo:rerun-if-changed=src/demo.cc");
//!     println!("cargo:rerun-if-changed=include/demo.h");
//! }
//! ```
//!
//! A runnable working setup with this build script is shown in the *demo*
//! directory of [https://github.com/dtolnay/cxx].
//!
//! [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
//!
//!

//!
//! # Alternatives
//!
//! For use in non-Cargo builds like Bazel or Buck, CXX provides an
//! alternate way of invoking the C++ code generator as a standalone command
//! line tool. The tool is packaged as the `cxxbridge-cmd` crate.
//!
//! ```bash
//! $ cargo install cxxbridge-cmd  # or build it from the repo
//!
//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
//! ```

#![allow(
    clippy::inherent_to_string,
    clippy::needless_doctest_main,
    clippy::new_without_default,
    clippy::or_fun_call,
    clippy::toplevel_ref_arg
)]

mod cargo;
mod error;
mod gen;
mod out;
mod paths;
mod syntax;

use crate::error::{Error, Result};
use crate::gen::error::report;
use crate::gen::Opt;
use crate::paths::{PathExt, TargetDir};
use cc::Build;
use std::collections::BTreeMap;
use std::env;
use std::ffi::{OsStr, OsString};
use std::io::{self, Write};
use std::iter;
use std::path::{Path, PathBuf};
use std::process;

/// This returns a [`cc::Build`] on which you should continue to set up any
/// additional source files or compiler flags, and lastly call its [`compile`]
/// method to execute the C++ build.
///
/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
#[must_use]
pub fn bridge(rust_source_file: impl AsRef<Path>) -> Build {
    bridges(iter::once(rust_source_file))
}

/// `cxx_build::bridge` but for when more than one file contains a
/// #\[cxx::bridge\] module.
///
/// ```no_run
/// let source_files = vec!["src/main.rs", "src/path/to/other.rs"];
/// cxx_build::bridges(source_files)
///     .file("src/demo.cc")
///     .flag_if_supported("-std=c++11")
///     .compile("cxxbridge-demo");
/// ```
#[must_use]
pub fn bridges(rust_source_files: impl IntoIterator<Item = impl AsRef<Path>>) -> Build {
    let ref mut rust_source_files = rust_source_files.into_iter();
    build(rust_source_files).unwrap_or_else(|err| {
        let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {}\n\n", report(err));
        process::exit(1);
    })
}

struct Project {
    package_name: OsString,
    manifest_dir: PathBuf,
    // Output directory as received from Cargo.
    out_dir: PathBuf,
    // Directory into which to symlink all generated code.
    //
    // This is *not* used for an #include path, only as a debugging convenience.
    // Normally available at target/cxxbridge/ if we are able to know where the
    // target dir is, otherwise under a common scratch dir.
    //
    // The reason this isn't the #include dir is that we do not want builds to
    // have access to headers from arbitrary other parts of the dependency
    // graph. Using a global directory for all builds would be both a race
    // condition depending on what order Cargo randomly executes the build
    // scripts, as well as semantically undesirable for builds not to have to
    // declare their real dependencies.
    shared_dir: PathBuf,
}

impl Project {
    fn init() -> Result<Self> {
        let package_name = env_os("CARGO_PKG_NAME")?;
        let manifest_dir = paths::manifest_dir()?;
        let out_dir = paths::out_dir()?;

        let target_dir = match cargo::target_dir(&out_dir) {
            target_dir @ TargetDir::Path(_) => target_dir,
            // Fallback if Cargo did not work.
            TargetDir::Unknown => paths::search_parents_for_target_dir(&out_dir),
        };

        let shared_dir = match target_dir {
            TargetDir::Path(target_dir) => target_dir.join("cxxbridge"),
            // Use cxx-build's OUT_DIR.
            TargetDir::Unknown => PathBuf::from(env!("OUT_DIR")),
        };

        Ok(Project {
            package_name,
            manifest_dir,
            out_dir,
            shared_dir,
        })
    }
}

// We lay out the OUT_DIR as follows. Everything is namespaced under a cxxbridge
// subdirectory to avoid stomping on other things that the caller's build script
// might be doing inside OUT_DIR.
//
//     $OUT_DIR/
//        cxxbridge/
//           crate/
//              $CARGO_PKG_NAME -> $CARGO_MANIFEST_DIR
//           include/
//              rust/
//                 cxx.h
//              $CARGO_PKG_NAME/
//                 .../
//                    lib.rs.h
//           sources/
//              $CARGO_PKG_NAME/
//                 .../
//                    lib.rs.cc
//
// The crate/ and include/ directories are placed on the #include path for the
// current build as well as for downstream builds that have a direct dependency
// on the current crate.
fn build(rust_source_files: &mut dyn Iterator<Item = impl AsRef<Path>>) -> Result<Build> {
    let ref prj = Project::init()?;

    let ref crate_dir = make_crate_dir(prj);
    let ref include_dir = make_include_dir(prj)?;

    let mut build = Build::new();
    build.cpp(true);
    build.cpp_link_stdlib(None); // linked via link-cplusplus crate

    for path in rust_source_files {
        generate_bridge(prj, &mut build, path.as_ref())?;
    }

    eprintln!("\nCXX include path:");
    build.include(include_dir);
    eprintln!("  {}", include_dir.display());
    if let Some(crate_dir) = crate_dir {
        // Placed after the generated code directory (include_dir) on the
        // include line so that `#include "path/to/file.rs"` from C++
        // "magically" works and refers to the API generated from that Rust
        // source file.
        build.include(crate_dir);
        eprintln!("  {}", crate_dir.display());
    }
    for dep in env_include_dirs() {
        build.include(&dep);
        eprintln!("  {}", dep.display());
    }
    Ok(build)
}

fn env_include_dirs() -> impl Iterator<Item = PathBuf> {
    let mut env_include_dirs = BTreeMap::new();
    for (k, v) in env::vars_os() {
        let mut k = k.to_string_lossy().into_owned();
        // Only variables set from a build script of direct dependencies are
        // observable. That's exactly what we want! Your crate needs to declare
        // a direct dependency on the other crate in order to be able to
        // #include its headers.
        //
        // Also, they're only observable if the dependency's manifest contains a
        // `links` key. This is important because Cargo imposes no ordering on
        // the execution of build scripts without a `links` key. When exposing a
        // generated header for the current crate to #include, we need to be
        // sure the dependency's build script has already executed and emitted
        // that generated header.
        //
        // References:
        //   - https://doc.rust-lang.org/cargo/reference/build-scripts.html#the-links-manifest-key
        //   - https://doc.rust-lang.org/cargo/reference/build-script-examples.html#using-another-sys-crate
        if k.starts_with("DEP_") {
            if k.ends_with("_CXXBRIDGE_INCLUDE") {
                // Tweak to ensure sorted before the other one, for the same
                // reason as the comment on ordering of include_dir vs crate_dir
                // above.
                k.replace_range(k.len() - "INCLUDE".len().., "0");
                env_include_dirs.insert(k, PathBuf::from(v));
            } else if k.ends_with("_CXXBRIDGE_CRATE") {
                k.replace_range(k.len() - "CRATE".len().., "1");
                env_include_dirs.insert(k, PathBuf::from(v));
            }
        }
    }
    env_include_dirs.into_iter().map(|entry| entry.1)
}

fn make_crate_dir(prj: &Project) -> Option<PathBuf> {
    let crate_dir = prj.out_dir.join("cxxbridge").join("crate");
    let link = crate_dir.join(&prj.package_name);
    if out::symlink_dir(&prj.manifest_dir, link).is_ok() {
        println!("cargo:CXXBRIDGE_CRATE={}", crate_dir.to_string_lossy());
        Some(crate_dir)
    } else {
        None
    }
}

fn make_include_dir(prj: &Project) -> Result<PathBuf> {
    let include_dir = prj.out_dir.join("cxxbridge").join("include");
    let cxx_h = include_dir.join("rust").join("cxx.h");
    let ref shared_cxx_h = prj.shared_dir.join("rust").join("cxx.h");
    if let Some(ref original) = env::var_os("DEP_CXXBRIDGE04_HEADER") {
        out::symlink_file(original, cxx_h)?;
        out::symlink_file(original, shared_cxx_h)?;
    } else {
        out::write(shared_cxx_h, gen::include::HEADER.as_bytes())?;
        out::symlink_file(shared_cxx_h, cxx_h)?;
    }
    println!("cargo:CXXBRIDGE_INCLUDE={}", include_dir.to_string_lossy());
    Ok(include_dir)
}

fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) -> Result<()> {
    let opt = Opt::default();
    let generated = gen::generate_from_path(rust_source_file, &opt);
    let ref rel_path = paths::local_relative_path(rust_source_file);

    let cxxbridge = prj.out_dir.join("cxxbridge");
    let include_dir = cxxbridge.join("include").join(&prj.package_name);
    let sources_dir = cxxbridge.join("sources").join(&prj.package_name);

    let ref rel_path_h = rel_path.with_appended_extension(".h");
    let ref header_path = include_dir.join(rel_path_h);
    out::write(header_path, &generated.header)?;

    let ref link_path = include_dir.join(rel_path);
    let _ = out::symlink_file(header_path, link_path);

    let ref rel_path_cc = rel_path.with_appended_extension(".cc");
    let ref implementation_path = sources_dir.join(rel_path_cc);
    out::write(implementation_path, &generated.implementation)?;
    build.file(implementation_path);

    let shared_h = prj.shared_dir.join(&prj.package_name).join(rel_path_h);
    let shared_cc = prj.shared_dir.join(&prj.package_name).join(rel_path_cc);
    let _ = out::symlink_file(header_path, shared_h);
    let _ = out::symlink_file(implementation_path, shared_cc);
    Ok(())
}

fn env_os(key: impl AsRef<OsStr>) -> Result<OsString> {
    let key = key.as_ref();
    env::var_os(key).ok_or_else(|| Error::NoEnv(key.to_owned()))
}
<|endoftext|>


<commit_before>//! Tests individual commands via `reply`

use std::collections::HashSet;

use rustc_serialize::json::{Json, ToJson};

use super::*;
use super::super::channel;

use registry;
use registry::tests as regtests;

const PING: &'static str =     r#"{ "type":"ping" }"#;
const COMMANDS: &'static str = r#"{ "type":"commands" }"#;
const VERSION: &'static str =  r#"{ "type":"version" }"#;

const RUN_COMMAND: &'static str =     r#"{"type":"run", "key":"command" }"#;
const RUN_PANIC_COMMAND: &'static str=r#"{"type":"run","key":"panic_command"}"#;
const RUN_BAD_KEY: &'static str =     r#"{"type":"run", "key":"non_command" }"#;
const RUN_NO_KEY: &'static str =      r#"{"type":"run" }"#;

const GET_OBJECT: &'static str =     r#"{ "type":"get", "key":"point" }"#;
const GET_PROP: &'static str =       r#"{ "type":"get", "key":"get_prop" }"#;
const GET_READONLY: &'static str =   r#"{ "type":"get", "key":"readonly" }"#;
const GET_WRITEONLY: &'static str =  r#"{ "type":"get", "key":"writeonly" }"#;
const GET_PROP_WRITE: &'static str = r#"{ "type":"get", "key":"set_prop" }"#;
const GET_NO_KEY: &'static str =     r#"{ "type":"get" }"#;
const GET_BAD_KEY: &'static str =   r#"{ "type":"get", "key":"novalue" }"#;

const SET_OBJECT: &'static str
    = r#"{ "type":"set", "key":"bool", "value":false }"#;
const SET_PROP: &'static str
    = r#"{ "type":"set", "key":"prop", "value":null }"#;
const SET_READONLY: &'static str
    = r#"{ "type":"set", "key":"readonly", "value":12 }"#;
const SET_WRITEONLY: &'static str
    = r#"{ "type":"set", "key":"writeonly", "value":11 }"#;
const SET_PROP_READ: &'static str
    = r#"{ "type":"set", "key":"prop_read", "value":"asdf" }"#;
const SET_NEW_KEY: &'static str
    = r#"{ "type":"set", "key":"new_key", "value":"value" }"#;
const SET_NO_PERMS: &'static str
    = r#"{ "type":"set", "key":"noperms", "value":"something" }"#;
const SET_NO_KEY: &'static str
    = r#"{ "type":"set", "value":12 }"#;
const SET_NO_VALUE: &'static str
    = r#"{ "type":"set", "key":"foo" }"#;
const SET_BAD_KEY_TYPE: &'static str
    = r#"{ "type":"set", "key":12 }"#;

const EXISTS_OBJECT_RW: &'static str =  r#"{"type":"exists","key":"null" }"#;
const EXISTS_PROP: &'static str =       r#"{"type":"exists","key":"prop" }"#;
const EXISTS_PROP_READ: &'static str =  r#"{"type":"exists","key":"get_prop"}"#;
const EXISTS_PROP_WRITE: &'static str = r#"{"type":"exists","key":"set_prop"}"#;
const EXISTS_OBJECT_READ:&'static str = r#"{"type":"exists","key":"readonly"}"#;
const EXISTS_OBJECT_WRITE:&'static str= r#"{"type":"exists","key":"writeonly"}"#;
const EXISTS_BAD_KEY: &'static str =    r#"{"type":"exists","key": "nope"}"#;

const BAD_NO_REQUEST: &'static str = r#"{ "key":"foo", "value":"bar" }"#;
const BAD_INVALID_REQUEST: &'static str = r#"{ "type":"foo" }"#;
const BAD_SET_NO_KEY: &'static str = r#"{ "type":"set", "value":12 }"#;
const BAD_SET_NO_VALUE: &'static str = r#"{ "type":"set", "key":"f64" }"#;
const BAD_RUN_NO_COMMAND: &'static str = r#"{ "type":"run" }"#;
const BAD_RUN_EXTRA_FIELDS: &'static str =
    r#"{ "type":"run", "key":"command", "foo":"bar" }"#;
const BAD_RUN_U64_COMMAND: &'static str = r#"{ "type":"run", "key":12 }"#;
const BAD_GET_OBJECT_KEY: &'static str = r#"{ "type":"get", "key": 12 }"#;
const BAD_REQUEST_IS_A_NUMBER: &'static str = r#"23"#;

macro_rules! reply {
    ($json:expr) => {
        super::super::command::reply(Json::from_str($json)
                                           .expect("Couldn't parse json"))
            .unwrap_or_else(|j| j)
    }
}

#[test]
fn ping() {
    let reply = reply!(PING);
    assert_eq!(reply, channel::success_json());
}

#[test]
fn commands() {
    let mut reply = reply!(COMMANDS);

    let mut obj = reply.as_object_mut()
        .expect("commands: reply not object");
    let mut value = obj.remove("value")
        .expect("commands: reply: no 'value'");
    let val_arr = value.as_array_mut()
        .expect("commands: reply: 'value' not array");
    let mut set = HashSet::new();
    for val in val_arr {
        set.insert(val.as_string()
                   .expect("commands: reply: 'value' not string array"));
    }
    assert_eq!(set.len(), 7);
    let desired = &["get", "set", "exists", "run", "version", "commands", "ping"];
    for com in desired.iter() {
        assert!(set.contains(com), "Missing command {}", com);
    }
}

#[test]
fn version() {
    let mut reply = reply!(VERSION);
    let version = reply.as_object_mut().expect("version: reply not object")
        .remove("value").expect("version: reply: no 'value'")
        .as_u64().expect("version: reply not u64");

    assert_eq!(version, super::super::VERSION);
}

#[test]
fn run_command() {
    let reply = reply!(RUN_COMMAND);
    assert_eq!(reply, channel::success_json());
}

// Note: If a command were to panic in way-cooler, the thread servicing that
// IPC connection would shut down. However, reply! is routing around that and
// everything is being run in each test thread. This is more of a general way
// of making sure commands are being run and we are aware of them.

#[test]
#[should_panic(reason = "panic_command panic")]
fn run_panic_command() {
    let reply = reply!(RUN_PANIC_COMMAND);
}

#[test]
fn command_bad_args() {
    assert_eq!(reply!(RUN_BAD_KEY), Json::Object(json_object!{
        "type" => "error",
        "reason" => "command not found"
    }));
    assert_eq!(reply!(RUN_NO_KEY), Json::Object(json_object!{
        "type" => "error",
        "reason" => "missing message field",
        "missing" => "key",
        "expected" => "String"
    }));
}

#[test]
fn get_stuff() {
    assert_eq!(reply!(GET_OBJECT),
               channel::value_json(registry::tests::POINT.to_json()));
    assert_eq!(reply!(GET_PROP),
               channel::value_json(json!(registry::tests::PROP_GET_RESULT)));
    assert_eq!(reply!(GET_READONLY),
               channel::value_json(json!(registry::tests::READONLY)));
    assert_eq!(reply!(GET_WRITEONLY),
               channel::value_json(json!(registry::tests::WRITEONLY)));
    assert_eq!(reply!(GET_PROP_WRITE),
               channel::error_json("cannot get that key".to_string()));
    assert_eq!(reply!(GET_NO_KEY),
               channel::error_expecting_key("key", "String"));
    assert_eq!(reply!(GET_BAD_KEY),
               channel::error_json("key not found".to_string()));
}

#[test]
fn set_stuff() {
    let error_set = channel::error_json("cannot set that key".to_string());
    assert_eq!(reply!(SET_OBJECT), channel::success_json());
    assert_eq!(reply!(SET_PROP), channel::success_json());
    assert_eq!(reply!(SET_READONLY), error_set);
    assert_eq!(reply!(SET_WRITEONLY), channel::success_json());
    assert_eq!(reply!(SET_PROP_READ), error_set);
    assert_eq!(reply!(SET_NO_PERMS), error_set);
    assert_eq!(reply!(SET_NEW_KEY),
               channel::error_json("key not found".to_string()));
    assert_eq!(reply!(SET_NO_KEY),
               channel::error_expecting_key("key", "String"));
    assert_eq!(reply!(SET_BAD_KEY_TYPE),
               channel::error_expecting_key("key", "String"));
    assert_eq!(reply!(SET_NO_VALUE),
               channel::error_expecting_key("Value", "any"));
}
<commit_msg>Fix most of the tests<commit_after>//! Tests individual commands via `reply`

use std::collections::HashSet;

use rustc_serialize::json::{Json, ToJson};

use super::*;
use super::super::channel;

use registry;
use registry::tests as regtests;

const PING: &'static str =     r#"{ "type":"ping" }"#;
const COMMANDS: &'static str = r#"{ "type":"commands" }"#;
const VERSION: &'static str =  r#"{ "type":"version" }"#;

const RUN_COMMAND: &'static str =     r#"{"type":"run", "key":"command" }"#;
const RUN_PANIC_COMMAND: &'static str=r#"{"type":"run","key":"panic_command"}"#;
const RUN_BAD_KEY: &'static str =     r#"{"type":"run", "key":"non_command" }"#;
const RUN_NO_KEY: &'static str =      r#"{"type":"run" }"#;

const GET_OBJECT: &'static str =     r#"{ "type":"get", "key":"point" }"#;
const GET_PROP: &'static str =       r#"{ "type":"get", "key":"get_prop" }"#;
const GET_READONLY: &'static str =   r#"{ "type":"get", "key":"readonly" }"#;
const GET_WRITEONLY: &'static str =  r#"{ "type":"get", "key":"writeonly" }"#;
const GET_PROP_WRITE: &'static str = r#"{ "type":"get", "key":"set_prop" }"#;
const GET_NO_KEY: &'static str =     r#"{ "type":"get" }"#;
const GET_BAD_KEY: &'static str =   r#"{ "type":"get", "key":"novalue" }"#;

const SET_OBJECT: &'static str
    = r#"{ "type":"set", "key":"ipc_test_bool", "value":false }"#;
const SET_PROP: &'static str
    = r#"{ "type":"set", "key":"prop", "value":null }"#;
const SET_READONLY: &'static str
    = r#"{ "type":"set", "key":"readonly", "value":12 }"#;
const SET_WRITEONLY: &'static str
    = r#"{ "type":"set", "key":"ipc_test_writeonly", "value":11 }"#;
const SET_PROP_READ: &'static str
    = r#"{ "type":"set", "key":"prop_read", "value":"asdf" }"#;
const SET_NEW_KEY: &'static str
    = r#"{ "type":"set", "key":"new_key", "value":"value" }"#;
const SET_NO_PERMS: &'static str
    = r#"{ "type":"set", "key":"noperms", "value":"something" }"#;
const SET_NO_KEY: &'static str
    = r#"{ "type":"set", "value":12 }"#;
const SET_NO_VALUE: &'static str
    = r#"{ "type":"set", "key":"foo" }"#;
const SET_BAD_KEY_TYPE: &'static str
    = r#"{ "type":"set", "key":12 }"#;

const EXISTS_OBJECT_RW: &'static str =  r#"{"type":"exists","key":"null" }"#;
const EXISTS_PROP: &'static str =       r#"{"type":"exists","key":"prop" }"#;
const EXISTS_PROP_READ: &'static str =  r#"{"type":"exists","key":"get_prop"}"#;
const EXISTS_PROP_WRITE: &'static str = r#"{"type":"exists","key":"set_prop"}"#;
const EXISTS_OBJECT_READ:&'static str = r#"{"type":"exists","key":"readonly"}"#;
const EXISTS_OBJECT_WRITE:&'static str= r#"{"type":"exists","key":"writeonly"}"#;
const EXISTS_BAD_KEY: &'static str =    r#"{"type":"exists","key": "nope"}"#;

const BAD_NO_REQUEST: &'static str = r#"{ "key":"foo", "value":"bar" }"#;
const BAD_INVALID_REQUEST: &'static str = r#"{ "type":"foo" }"#;
const BAD_SET_NO_KEY: &'static str = r#"{ "type":"set", "value":12 }"#;
const BAD_SET_NO_VALUE: &'static str = r#"{ "type":"set", "key":"f64" }"#;
const BAD_RUN_NO_COMMAND: &'static str = r#"{ "type":"run" }"#;
const BAD_RUN_EXTRA_FIELDS: &'static str =
    r#"{ "type":"run", "key":"command", "foo":"bar" }"#;
const BAD_RUN_U64_COMMAND: &'static str = r#"{ "type":"run", "key":12 }"#;
const BAD_GET_OBJECT_KEY: &'static str = r#"{ "type":"get", "key": 12 }"#;
const BAD_REQUEST_IS_A_NUMBER: &'static str = r#"23"#;

macro_rules! reply {
    ($json:expr) => {
        super::super::command::reply(Json::from_str($json)
                                           .expect("Couldn't parse json"))
            .unwrap_or_else(|j| j)
    }
}

#[test]
fn ping() {
    let reply = reply!(PING);
    assert_eq!(reply, channel::success_json());
}

#[test]
fn commands() {
    let mut reply = reply!(COMMANDS);

    let mut obj = reply.as_object_mut()
        .expect("commands: reply not object");
    let mut value = obj.remove("value")
        .expect("commands: reply: no 'value'");
    let val_arr = value.as_array_mut()
        .expect("commands: reply: 'value' not array");
    let mut set = HashSet::new();
    for val in val_arr {
        set.insert(val.as_string()
                   .expect("commands: reply: 'value' not string array"));
    }
    assert_eq!(set.len(), 7);
    let desired = &["get", "set", "exists", "run", "version", "commands", "ping"];
    for com in desired.iter() {
        assert!(set.contains(com), "Missing command {}", com);
    }
}

#[test]
fn version() {
    let mut reply = reply!(VERSION);
    let version = reply.as_object_mut().expect("version: reply not object")
        .remove("value").expect("version: reply: no 'value'")
        .as_u64().expect("version: reply not u64");

    assert_eq!(version, super::super::VERSION);
}

#[test]
fn run_command() {
    let reply = reply!(RUN_COMMAND);
    assert_eq!(reply, channel::success_json());
}

// Note: If a command were to panic in way-cooler, the thread servicing that
// IPC connection would shut down. However, reply! is routing around that and
// everything is being run in each test thread. This is more of a general way
// of making sure commands are being run and we are aware of them.

#[test]
#[should_panic(reason = "panic_command panic")]
fn run_panic_command() {
    let reply = reply!(RUN_PANIC_COMMAND);
}

#[test]
fn command_bad_args() {
    assert_eq!(reply!(RUN_BAD_KEY), Json::Object(json_object!{
        "type" => "error",
        "reason" => "command not found"
    }));
    assert_eq!(reply!(RUN_NO_KEY), Json::Object(json_object!{
        "type" => "error",
        "reason" => "missing message field",
        "missing" => "key",
        "expected" => "String"
    }));
}

#[test]
fn get_stuff() {
    assert_eq!(reply!(GET_OBJECT),
               channel::value_json(registry::tests::POINT.to_json()));
    assert_eq!(reply!(GET_PROP),
               channel::value_json(json!(registry::tests::PROP_GET_RESULT)));
    assert_eq!(reply!(GET_READONLY),
               channel::value_json(json!(registry::tests::READONLY)));
    assert_eq!(reply!(GET_WRITEONLY),
               channel::value_json(json!(registry::tests::WRITEONLY)));
    assert_eq!(reply!(GET_PROP_WRITE),
               channel::error_json("cannot get that key".to_string()));
    assert_eq!(reply!(GET_NO_KEY),
               channel::error_expecting_key("key", "String"));
    assert_eq!(reply!(GET_BAD_KEY),
               channel::error_json("key not found".to_string()));
}

#[test]
fn set_stuff() {
    use registry::AccessFlags;
    let error_set = channel::error_json("cannot set that key".to_string());
    registry::insert_json("ipc_test_bool".to_string(),
                          AccessFlags::all(),
                          true.to_json());
    registry::insert_json("ipc_test_writeonly".to_string(),
                          AccessFlags::WRITE(),
                          false.to_json());
    assert_eq!(reply!(SET_OBJECT), channel::success_json());
    assert_eq!(reply!(SET_PROP), channel::success_json());
    assert_eq!(reply!(SET_READONLY), error_set);
    assert_eq!(reply!(SET_WRITEONLY), channel::success_json());
    assert_eq!(reply!(SET_PROP_READ), error_set);
    assert_eq!(reply!(SET_NO_PERMS), error_set);
    assert_eq!(reply!(SET_NEW_KEY),
               channel::error_json("key not found".to_string()));
    assert_eq!(reply!(SET_NO_KEY),
               channel::error_expecting_key("key", "String"));
    assert_eq!(reply!(SET_BAD_KEY_TYPE),
               channel::error_expecting_key("key", "String"));
    assert_eq!(reply!(SET_NO_VALUE),
               channel::error_expecting_key("Value", "any"));
}
<|endoftext|>


<commit_before>/*!
Calculate styles for Nodes based on SelectResults, resolving inherited values
*/

use dom::node::Node;
use newcss::color::{Color, rgba};
use newcss::values::{CSSValue, Specified, Inherit, Length, Px, CSSBorderWidth, BdrWidthLength};
use newcss::ComputedStyle;

pub trait ComputeStyles {
    fn compute_background_color(&self) -> Color;
    fn compute_border_top_width(&self) -> CSSBorderWidth;
    fn compute_border_right_width(&self) -> CSSBorderWidth;
    fn compute_border_bottom_width(&self) -> CSSBorderWidth;
    fn compute_border_left_width(&self) -> CSSBorderWidth;
}

impl Node: ComputeStyles {
    fn compute_background_color(&self) -> Color {
        compute(self, rgba(0, 0, 0, 0.0), |cs| cs.background_color() )
    }

    fn compute_border_top_width(&self) -> CSSBorderWidth {
        compute(self, BdrWidthLength(Px(0.0)), |cs| cs.border_top_width() )
    }

    fn compute_border_right_width(&self) -> CSSBorderWidth {
        compute(self, BdrWidthLength(Px(0.0)), |cs| cs.border_right_width() )
    }

    fn compute_border_bottom_width(&self) -> CSSBorderWidth {
        compute(self, BdrWidthLength(Px(0.0)), |cs| cs.border_bottom_width() )
    }

    fn compute_border_left_width(&self) -> CSSBorderWidth {
        compute(self, BdrWidthLength(Px(0.0)), |cs| cs.border_left_width() )
    }
}

fn compute<T>(node: &Node, default: T, get: &fn(cs: ComputedStyle) -> CSSValue<T>) -> T {
    let style = node.get_style();
    let computed = style.computed_style();
    let value = get(computed);
    match move value {
        Inherit => /* FIXME: need inheritance */ move default,
        Specified(move value) => move value,
        _ => fail
    }
}<commit_msg>Clean up css::compute<commit_after>/*!
Calculates computed Node styles, based on CSS SelectResults.

These methods mostly defer to the Node's ComputedStyle object.
The only exception is that this is where inheritance is resolved.
*/

use dom::node::Node;
use newcss::color::{Color, rgba};
use newcss::values::{CSSValue, Specified, Inherit, Length, Px, CSSBorderWidth, BdrWidthLength};
use newcss::ComputedStyle;

pub trait ComputeStyles {
    fn compute_background_color(&self) -> Color;
    fn compute_border_top_width(&self) -> CSSBorderWidth;
    fn compute_border_right_width(&self) -> CSSBorderWidth;
    fn compute_border_bottom_width(&self) -> CSSBorderWidth;
    fn compute_border_left_width(&self) -> CSSBorderWidth;
}

impl Node: ComputeStyles {
    fn compute_background_color(&self) -> Color {
        resolve(self, rgba(0, 0, 0, 0.0), |cs| cs.background_color() )
    }

    fn compute_border_top_width(&self) -> CSSBorderWidth {
        resolve(self, BdrWidthLength(Px(0.0)), |cs| cs.border_top_width() )
    }

    fn compute_border_right_width(&self) -> CSSBorderWidth {
        resolve(self, BdrWidthLength(Px(0.0)), |cs| cs.border_right_width() )
    }

    fn compute_border_bottom_width(&self) -> CSSBorderWidth {
        resolve(self, BdrWidthLength(Px(0.0)), |cs| cs.border_bottom_width() )
    }

    fn compute_border_left_width(&self) -> CSSBorderWidth {
        resolve(self, BdrWidthLength(Px(0.0)), |cs| cs.border_left_width() )
    }
}

fn resolve<T>(node: &Node, default: T, get: &fn(cs: ComputedStyle) -> CSSValue<T>) -> T {
    let style = node.get_style();
    let computed = style.computed_style();
    let value = get(computed);
    match move value {
        Inherit => /* FIXME: need inheritance */ move default,
        Specified(move value) => move value,
        _ => fail
    }
}<|endoftext|>


<commit_before>use std::io::{self, Write};

fn emit_prompt() {
    print!("temp> ");
    io::stdout().flush().unwrap();
} // end emit_prompt

/*fn to_celsius(temp: f64) -> f64 {
    0.0
}

fn to_fahrenheit(temp: f64) -> f64 {
    0.0
}

fn to_kelvin(temp: f64) -> f64 {
    0.0
}
*/
fn main() {
    println!("Temperature Converter");
    println!("please enter a temperature followed by a letter for the units.");
    println!("Examples: 23f, 12.6c, 42.0k (Fahrenheit, Celsius, Kelvin)");

    loop {
        emit_prompt();

        let mut value = String::new();
        io::stdin().read_line(&mut value)
            .expect("Failed to read line");
        let value = value.trim();

        // allow a graceful exit from the program.
        if value == "quit" {
            break;
        } else if value == "exit" {
            break;
        }

        println!("You gave me: {}", value);
    }
}
<commit_msg>initial changes to use a Struct.<commit_after>use std::io::{self, Write};

fn emit_prompt() {
    print!("temp> ");
    io::stdout().flush().unwrap();
} // end emit_prompt

struct Temp {
    deg_celsius: f64,
    deg_fahrenheit: f64,
    deg_kelvin: f64,
}

impl Temp {
    fn convert(temp: f64, from_units: char, to_units: char) -> f64 {
        0.0
    }
}

fn main() {
    println!("Temperature Converter");
    println!("please enter a temperature followed by a letter for the units.");
    println!("Examples: 23f, 12.6c, 42.0k (Fahrenheit, Celsius, Kelvin)");

    loop {
        emit_prompt();

        let mut value = String::new();
        io::stdin().read_line(&mut value).expect("Failed to read line");
        let value = value.trim();

        // allow a graceful exit from the program.
        if value == "quit" {
            break;
        } else if value == "exit" {
            break;
        }

        println!("You gave me: {}", value);
    }
}
<|endoftext|>


<commit_before>use storage::Storage;
use {zero, DVector, Dim, Dynamic, Matrix, Real, VecStorage, Vector, U1};
use std::cmp;

///
/// The output is the full discrete linear convolution of the inputs
///
pub fn convolve_full<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
    vector: Vector<R, D, S>,
    kernel: Vector<R, E, Q>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
    let vec = vector.len();
    let ker = kernel.len();

    if vec == 0 || ker == 0 {
        panic!("Convolve's inputs must not be 0-sized. ");
    }

    if ker > vec {
        return convolve_full(kernel, vector);
    }

    let newlen = vec + ker - 1;

    let mut conv = DVector::<R>::zeros(newlen);

    for i in 0..newlen {
        let u_i = if i > ker { i - ker } else { 0 };
        let u_f = cmp::min(i, vec - 1);

        if u_i == u_f {
            conv[i] += vector[u_i] * kernel[(i - u_i)];
        } else {
            for u in u_i..(u_f + 1) {
                if i - u < ker {
                    conv[i] += vector[u] * kernel[(i - u)];
                }
            }
        }
    }
    conv
}

///
/// The output consists only of those elements that do not rely on the zero-padding.
///
pub fn convolve_valid<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
    vector: Vector<R, D, S>,
    kernel: Vector<R, E, Q>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
    let vec = vector.len();
    let ker = kernel.len();

    if vec == 0 || ker == 0 {
        panic!("Convolve's inputs must not be 0-sized. ");
    }

    if ker > vec {
        return convolve_valid(kernel, vector);
    }

    let newlen = vec - ker + 1;

    let mut conv = DVector::<R>::zeros(newlen);

    for i in 0..newlen {
        for j in 0..ker {
            conv[i] += vector[i + j] * kernel[ker - j - 1];
        }
    }
    conv
}

///
/// The output is the same size as in1, centered with respect to the ‘full’ output.
///
pub fn convolve_same<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
    vector: Vector<R, D, S>,
    kernel: Vector<R, E, Q>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
    let vec = vector.len();
    let ker = kernel.len();

    if vec == 0 || ker == 0 {
        panic!("Convolve's inputs must not be 0-sized. ");
    }

    if ker > vec {
        return convolve_same(kernel, vector);
    }

    let mut conv = DVector::<R>::zeros(vec);

    for i in 0..vec {
        for j in 0..ker {
            let val = if i + j < 1 || i + j >= vec + 1 {
                zero::<R>()
            } else {
                vector[i + j - 1]
            };
            conv[i] += val * kernel[ker - j - 1];
        }
    }
    conv
}<commit_msg>Quick fix to documentation<commit_after>use storage::Storage;
use {zero, DVector, Dim, Dynamic, Matrix, Real, VecStorage, Vector, U1};
use std::cmp;

///
/// The output is the full discrete linear convolution of the inputs
///
pub fn convolve_full<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
    vector: Vector<R, D, S>,
    kernel: Vector<R, E, Q>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
    let vec = vector.len();
    let ker = kernel.len();

    if vec == 0 || ker == 0 {
        panic!("Convolve's inputs must not be 0-sized. ");
    }

    if ker > vec {
        return convolve_full(kernel, vector);
    }

    let newlen = vec + ker - 1;

    let mut conv = DVector::<R>::zeros(newlen);

    for i in 0..newlen {
        let u_i = if i > ker { i - ker } else { 0 };
        let u_f = cmp::min(i, vec - 1);

        if u_i == u_f {
            conv[i] += vector[u_i] * kernel[(i - u_i)];
        } else {
            for u in u_i..(u_f + 1) {
                if i - u < ker {
                    conv[i] += vector[u] * kernel[(i - u)];
                }
            }
        }
    }
    conv
}

///
/// The output convolution consists only of those elements that do not rely on the zero-padding.
///
pub fn convolve_valid<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
    vector: Vector<R, D, S>,
    kernel: Vector<R, E, Q>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
    let vec = vector.len();
    let ker = kernel.len();

    if vec == 0 || ker == 0 {
        panic!("Convolve's inputs must not be 0-sized. ");
    }

    if ker > vec {
        return convolve_valid(kernel, vector);
    }

    let newlen = vec - ker + 1;

    let mut conv = DVector::<R>::zeros(newlen);

    for i in 0..newlen {
        for j in 0..ker {
            conv[i] += vector[i + j] * kernel[ker - j - 1];
        }
    }
    conv
}

///
/// The output convolution is the same size as vector, centered with respect to the ‘full’ output.
///
pub fn convolve_same<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
    vector: Vector<R, D, S>,
    kernel: Vector<R, E, Q>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
    let vec = vector.len();
    let ker = kernel.len();

    if vec == 0 || ker == 0 {
        panic!("Convolve's inputs must not be 0-sized. ");
    }

    if ker > vec {
        return convolve_same(kernel, vector);
    }

    let mut conv = DVector::<R>::zeros(vec);

    for i in 0..vec {
        for j in 0..ker {
            let val = if i + j < 1 || i + j >= vec + 1 {
                zero::<R>()
            } else {
                vector[i + j - 1]
            };
            conv[i] += val * kernel[ker - j - 1];
        }
    }
    conv
}<|endoftext|>