<commit_before>//! Shim which is passed to Cargo as "rustc" when running the bootstrap.
//!
//! This shim will take care of some various tasks that our build process
//! requires that Cargo can't quite do through normal configuration:
//!
//! 1. When compiling build scripts and build dependencies, we need a guaranteed
//!    full standard library available. The only compiler which actually has
//!    this is the snapshot, so we detect this situation and always compile with
//!    the snapshot compiler.
//! 2. We pass a bunch of `--cfg` and other flags based on what we're compiling
//!    (and this slightly differs based on a whether we're using a snapshot or
//!    not), so we do that all here.
//!
//! This may one day be replaced by RUSTFLAGS, but the dynamic nature of
//! switching compilers for the bootstrap and for build scripts will probably
//! never get replaced.

use std::env;
use std::path::PathBuf;
use std::process::Command;
use std::str::FromStr;
use std::time::Instant;

fn main() {
    let args = env::args_os().skip(1).collect::<Vec<_>>();

    // Detect whether or not we're a build script depending on whether --target
    // is passed (a bit janky...)
    let target = args.windows(2).find(|w| &*w[0] == "--target").and_then(|w| w[1].to_str());
    let version = args.iter().find(|w| &**w == "-vV");

    let verbose = match env::var("RUSTC_VERBOSE") {
        Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"),
        Err(_) => 0,
    };

    // Use a different compiler for build scripts, since there may not yet be a
    // libstd for the real compiler to use. However, if Cargo is attempting to
    // determine the version of the compiler, the real compiler needs to be
    // used. Currently, these two states are differentiated based on whether
    // --target and -vV is/isn't passed.
    let (rustc, libdir) = if target.is_none() && version.is_none() {
        ("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR")
    } else {
        ("RUSTC_REAL", "RUSTC_LIBDIR")
    };
    let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
    let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
    let on_fail = env::var_os("RUSTC_ON_FAIL").map(Command::new);

    let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
    let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
    let mut dylib_path = bootstrap::util::dylib_path();
    dylib_path.insert(0, PathBuf::from(&libdir));

    let mut cmd = Command::new(rustc);
    cmd.args(&args).env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap());

    // Get the name of the crate we're compiling, if any.
    let crate_name =
        args.windows(2).find(|args| args[0] == "--crate-name").and_then(|args| args[1].to_str());

    if let Some(crate_name) = crate_name {
        if let Some(target) = env::var_os("RUSTC_TIME") {
            if target == "all"
                || target.into_string().unwrap().split(',').any(|c| c.trim() == crate_name)
            {
                cmd.arg("-Ztime");
            }
        }
    }

    // Print backtrace in case of ICE
    if env::var("RUSTC_BACKTRACE_ON_ICE").is_ok() && env::var("RUST_BACKTRACE").is_err() {
        cmd.env("RUST_BACKTRACE", "1");
    }

    if let Ok(lint_flags) = env::var("RUSTC_LINT_FLAGS") {
        cmd.args(lint_flags.split_whitespace());
    }

    if target.is_some() {
        // The stage0 compiler has a special sysroot distinct from what we
        // actually downloaded, so we just always pass the `--sysroot` option,
        // unless one is already set.
        if !args.iter().any(|arg| arg == "--sysroot") {
            cmd.arg("--sysroot").arg(&sysroot);
        }

        // If we're compiling specifically the `panic_abort` crate then we pass
        // the `-C panic=abort` option. Note that we do not do this for any
        // other crate intentionally as this is the only crate for now that we
        // ship with panic=abort.
        //
        // This... is a bit of a hack how we detect this. Ideally this
        // information should be encoded in the crate I guess? Would likely
        // require an RFC amendment to RFC 1513, however.
        //
        // `compiler_builtins` are unconditionally compiled with panic=abort to
        // workaround undefined references to `rust_eh_unwind_resume` generated
        // otherwise, see issue https://github.com/rust-lang/rust/issues/43095.
        if crate_name == Some("panic_abort")
            || crate_name == Some("compiler_builtins") && stage != "0"
        {
            cmd.arg("-C").arg("panic=abort");
        }
    } else {
        // FIXME(rust-lang/cargo#5754) we shouldn't be using special env vars
        // here, but rather Cargo should know what flags to pass rustc itself.

        // Override linker if necessary.
        if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
            cmd.arg(format!("-Clinker={}", host_linker));
        }
        if env::var_os("RUSTC_HOST_FUSE_LD_LLD").is_some() {
            cmd.arg("-Clink-args=-fuse-ld=lld");
        }

        if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") {
            if s == "true" {
                cmd.arg("-C").arg("target-feature=+crt-static");
            }
            if s == "false" {
                cmd.arg("-C").arg("target-feature=-crt-static");
            }
        }
    }

    if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") {
        cmd.arg("--remap-path-prefix").arg(&map);
    }

    // Force all crates compiled by this compiler to (a) be unstable and (b)
    // allow the `rustc_private` feature to link to other unstable crates
    // also in the sysroot. We also do this for host crates, since those
    // may be proc macros, in which case we might ship them.
    if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() && (stage != "0" || target.is_some()) {
        cmd.arg("-Z").arg("force-unstable-if-unmarked");
    }

    if verbose > 1 {
        let rust_env_vars =
            env::vars().filter(|(k, _)| k.starts_with("RUST") || k.starts_with("CARGO"));
        let prefix = match crate_name {
            Some(crate_name) => format!("rustc {}", crate_name),
            None => "rustc".to_string(),
        };
        for (i, (k, v)) in rust_env_vars.enumerate() {
            eprintln!("{} env[{}]: {:?}={:?}", prefix, i, k, v);
        }
        eprintln!("{} working directory: {}", prefix, env::current_dir().unwrap().display());
        eprintln!(
            "{} command: {:?}={:?} {:?}",
            prefix,
            bootstrap::util::dylib_path_var(),
            env::join_paths(&dylib_path).unwrap(),
            cmd,
        );
        eprintln!("{} sysroot: {:?}", prefix, sysroot);
        eprintln!("{} libdir: {:?}", prefix, libdir);
    }

    let start = Instant::now();
    let status = {
        let errmsg = format!("\nFailed to run:\n{:?}\n-------------", cmd);
        cmd.status().expect(&errmsg)
    };

    if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some()
        || env::var_os("RUSTC_PRINT_STEP_RUSAGE").is_some()
    {
        if let Some(crate_name) = crate_name {
            let dur = start.elapsed();
            let is_test = args.iter().any(|a| a == "--test");
            // If the user requested resource usage data, then
            // include that in addition to the timing output.
            let rusage_data =
                env::var_os("RUSTC_PRINT_STEP_RUSAGE").and_then(|_| format_rusage_data());
            eprintln!(
                "[RUSTC-TIMING] {} test:{} {}.{:03}{}{}",
                crate_name,
                is_test,
                dur.as_secs(),
                dur.subsec_millis(),
                if rusage_data.is_some() { " " } else { "" },
                rusage_data.unwrap_or(String::new()),
            );
        }
    }

    if status.success() {
        std::process::exit(0);
        // note: everything below here is unreachable. do not put code that
        // should run on success, after this block.
    }
    if verbose > 0 {
        println!("\nDid not run successfully: {}\n{:?}\n-------------", status, cmd);
    }

    if let Some(mut on_fail) = on_fail {
        on_fail.status().expect("Could not run the on_fail command");
    }

    // Preserve the exit code. In case of signal, exit with 0xfe since it's
    // awkward to preserve this status in a cross-platform way.
    match status.code() {
        Some(i) => std::process::exit(i),
        None => {
            eprintln!("rustc exited with {}", status);
            std::process::exit(0xfe);
        }
    }
}

#[cfg(not(unix))]
/// getrusage is not available on non-unix platforms. So for now, we do not
/// bother trying to make a shim for it.
fn format_rusage_data() -> Option<String> {
    None
}

#[cfg(unix)]
/// Tries to build a string with human readable data for several of the rusage
/// fields. Note that we are focusing mainly on data that we believe to be
/// supplied on Linux (the `rusage` struct has other fields in it but they are
/// currently unsupported by Linux).
fn format_rusage_data() -> Option<String> {
    let rusage: libc::rusage = unsafe {
        let mut recv = std::mem::zeroed();
        // -1 is RUSAGE_CHILDREN, which means to get the rusage for all children
        // (and grandchildren, etc) processes that have respectively terminated
        // and been waited for.
        let retval = libc::getrusage(-1, &mut recv);
        if retval != 0 {
            return None;
        }
        recv
    };
    // Mac OS X reports the maxrss in bytes, not kb.
    let divisor = if env::consts::OS == "macos" { 1024 } else { 1 };
    let maxrss = rusage.ru_maxrss + (divisor - 1) / divisor;

    let mut init_str = format!(
        "user: {USER_SEC}.{USER_USEC:03} \
         sys: {SYS_SEC}.{SYS_USEC:03} \
         max rss (kb): {MAXRSS}",
        USER_SEC = rusage.ru_utime.tv_sec,
        USER_USEC = rusage.ru_utime.tv_usec,
        SYS_SEC = rusage.ru_stime.tv_sec,
        SYS_USEC = rusage.ru_stime.tv_usec,
        MAXRSS = maxrss
    );

    // The remaining rusage stats vary in platform support. So we treat
    // uniformly zero values in each category as "not worth printing", since it
    // either means no events of that type occurred, or that the platform
    // does not support it.

    let minflt = rusage.ru_minflt;
    let majflt = rusage.ru_majflt;
    if minflt != 0 || majflt != 0 {
        init_str.push_str(&format!(" page reclaims: {} page faults: {}", minflt, majflt));
    }

    let inblock = rusage.ru_inblock;
    let oublock = rusage.ru_oublock;
    if inblock != 0 || oublock != 0 {
        init_str.push_str(&format!(" fs block inputs: {} fs block outputs: {}", inblock, oublock));
    }

    let nvcsw = rusage.ru_nvcsw;
    let nivcsw = rusage.ru_nivcsw;
    if nvcsw != 0 || nivcsw != 0 {
        init_str.push_str(&format!(
            " voluntary ctxt switches: {} involuntary ctxt switches: {}",
            nvcsw, nivcsw
        ));
    }

    return Some(init_str);
}
<commit_msg>Revise prefix a bit, adding both `--test` (conditionally) and `[RUSTC-SHIM]` unconditionally.<commit_after>//! Shim which is passed to Cargo as "rustc" when running the bootstrap.
//!
//! This shim will take care of some various tasks that our build process
//! requires that Cargo can't quite do through normal configuration:
//!
//! 1. When compiling build scripts and build dependencies, we need a guaranteed
//!    full standard library available. The only compiler which actually has
//!    this is the snapshot, so we detect this situation and always compile with
//!    the snapshot compiler.
//! 2. We pass a bunch of `--cfg` and other flags based on what we're compiling
//!    (and this slightly differs based on a whether we're using a snapshot or
//!    not), so we do that all here.
//!
//! This may one day be replaced by RUSTFLAGS, but the dynamic nature of
//! switching compilers for the bootstrap and for build scripts will probably
//! never get replaced.

use std::env;
use std::path::PathBuf;
use std::process::Command;
use std::str::FromStr;
use std::time::Instant;

fn main() {
    let args = env::args_os().skip(1).collect::<Vec<_>>();

    // Detect whether or not we're a build script depending on whether --target
    // is passed (a bit janky...)
    let target = args.windows(2).find(|w| &*w[0] == "--target").and_then(|w| w[1].to_str());
    let version = args.iter().find(|w| &**w == "-vV");

    let verbose = match env::var("RUSTC_VERBOSE") {
        Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"),
        Err(_) => 0,
    };

    // Use a different compiler for build scripts, since there may not yet be a
    // libstd for the real compiler to use. However, if Cargo is attempting to
    // determine the version of the compiler, the real compiler needs to be
    // used. Currently, these two states are differentiated based on whether
    // --target and -vV is/isn't passed.
    let (rustc, libdir) = if target.is_none() && version.is_none() {
        ("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR")
    } else {
        ("RUSTC_REAL", "RUSTC_LIBDIR")
    };
    let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
    let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
    let on_fail = env::var_os("RUSTC_ON_FAIL").map(Command::new);

    let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
    let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
    let mut dylib_path = bootstrap::util::dylib_path();
    dylib_path.insert(0, PathBuf::from(&libdir));

    let mut cmd = Command::new(rustc);
    cmd.args(&args).env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap());

    // Get the name of the crate we're compiling, if any.
    let crate_name =
        args.windows(2).find(|args| args[0] == "--crate-name").and_then(|args| args[1].to_str());

    if let Some(crate_name) = crate_name {
        if let Some(target) = env::var_os("RUSTC_TIME") {
            if target == "all"
                || target.into_string().unwrap().split(',').any(|c| c.trim() == crate_name)
            {
                cmd.arg("-Ztime");
            }
        }
    }

    // Print backtrace in case of ICE
    if env::var("RUSTC_BACKTRACE_ON_ICE").is_ok() && env::var("RUST_BACKTRACE").is_err() {
        cmd.env("RUST_BACKTRACE", "1");
    }

    if let Ok(lint_flags) = env::var("RUSTC_LINT_FLAGS") {
        cmd.args(lint_flags.split_whitespace());
    }

    if target.is_some() {
        // The stage0 compiler has a special sysroot distinct from what we
        // actually downloaded, so we just always pass the `--sysroot` option,
        // unless one is already set.
        if !args.iter().any(|arg| arg == "--sysroot") {
            cmd.arg("--sysroot").arg(&sysroot);
        }

        // If we're compiling specifically the `panic_abort` crate then we pass
        // the `-C panic=abort` option. Note that we do not do this for any
        // other crate intentionally as this is the only crate for now that we
        // ship with panic=abort.
        //
        // This... is a bit of a hack how we detect this. Ideally this
        // information should be encoded in the crate I guess? Would likely
        // require an RFC amendment to RFC 1513, however.
        //
        // `compiler_builtins` are unconditionally compiled with panic=abort to
        // workaround undefined references to `rust_eh_unwind_resume` generated
        // otherwise, see issue https://github.com/rust-lang/rust/issues/43095.
        if crate_name == Some("panic_abort")
            || crate_name == Some("compiler_builtins") && stage != "0"
        {
            cmd.arg("-C").arg("panic=abort");
        }
    } else {
        // FIXME(rust-lang/cargo#5754) we shouldn't be using special env vars
        // here, but rather Cargo should know what flags to pass rustc itself.

        // Override linker if necessary.
        if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
            cmd.arg(format!("-Clinker={}", host_linker));
        }
        if env::var_os("RUSTC_HOST_FUSE_LD_LLD").is_some() {
            cmd.arg("-Clink-args=-fuse-ld=lld");
        }

        if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") {
            if s == "true" {
                cmd.arg("-C").arg("target-feature=+crt-static");
            }
            if s == "false" {
                cmd.arg("-C").arg("target-feature=-crt-static");
            }
        }
    }

    if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") {
        cmd.arg("--remap-path-prefix").arg(&map);
    }

    // Force all crates compiled by this compiler to (a) be unstable and (b)
    // allow the `rustc_private` feature to link to other unstable crates
    // also in the sysroot. We also do this for host crates, since those
    // may be proc macros, in which case we might ship them.
    if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() && (stage != "0" || target.is_some()) {
        cmd.arg("-Z").arg("force-unstable-if-unmarked");
    }

    let is_test = args.iter().any(|a| a == "--test");
    if verbose > 1 {
        let rust_env_vars =
            env::vars().filter(|(k, _)| k.starts_with("RUST") || k.starts_with("CARGO"));
        let prefix = if is_test { "[RUSTC-SHIM] rustc --test" } else { "[RUSTC-SHIM] rustc" };
        let prefix = match crate_name {
            Some(crate_name) => format!("{} {}", prefix, crate_name),
            None => prefix.to_string(),
        };
        for (i, (k, v)) in rust_env_vars.enumerate() {
            eprintln!("{} env[{}]: {:?}={:?}", prefix, i, k, v);
        }
        eprintln!("{} working directory: {}", prefix, env::current_dir().unwrap().display());
        eprintln!(
            "{} command: {:?}={:?} {:?}",
            prefix,
            bootstrap::util::dylib_path_var(),
            env::join_paths(&dylib_path).unwrap(),
            cmd,
        );
        eprintln!("{} sysroot: {:?}", prefix, sysroot);
        eprintln!("{} libdir: {:?}", prefix, libdir);
    }

    let start = Instant::now();
    let status = {
        let errmsg = format!("\nFailed to run:\n{:?}\n-------------", cmd);
        cmd.status().expect(&errmsg)
    };

    if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some()
        || env::var_os("RUSTC_PRINT_STEP_RUSAGE").is_some()
    {
        if let Some(crate_name) = crate_name {
            let dur = start.elapsed();
            // If the user requested resource usage data, then
            // include that in addition to the timing output.
            let rusage_data =
                env::var_os("RUSTC_PRINT_STEP_RUSAGE").and_then(|_| format_rusage_data());
            eprintln!(
                "[RUSTC-TIMING] {} test:{} {}.{:03}{}{}",
                crate_name,
                is_test,
                dur.as_secs(),
                dur.subsec_millis(),
                if rusage_data.is_some() { " " } else { "" },
                rusage_data.unwrap_or(String::new()),
            );
        }
    }

    if status.success() {
        std::process::exit(0);
        // note: everything below here is unreachable. do not put code that
        // should run on success, after this block.
    }
    if verbose > 0 {
        println!("\nDid not run successfully: {}\n{:?}\n-------------", status, cmd);
    }

    if let Some(mut on_fail) = on_fail {
        on_fail.status().expect("Could not run the on_fail command");
    }

    // Preserve the exit code. In case of signal, exit with 0xfe since it's
    // awkward to preserve this status in a cross-platform way.
    match status.code() {
        Some(i) => std::process::exit(i),
        None => {
            eprintln!("rustc exited with {}", status);
            std::process::exit(0xfe);
        }
    }
}

#[cfg(not(unix))]
/// getrusage is not available on non-unix platforms. So for now, we do not
/// bother trying to make a shim for it.
fn format_rusage_data() -> Option<String> {
    None
}

#[cfg(unix)]
/// Tries to build a string with human readable data for several of the rusage
/// fields. Note that we are focusing mainly on data that we believe to be
/// supplied on Linux (the `rusage` struct has other fields in it but they are
/// currently unsupported by Linux).
fn format_rusage_data() -> Option<String> {
    let rusage: libc::rusage = unsafe {
        let mut recv = std::mem::zeroed();
        // -1 is RUSAGE_CHILDREN, which means to get the rusage for all children
        // (and grandchildren, etc) processes that have respectively terminated
        // and been waited for.
        let retval = libc::getrusage(-1, &mut recv);
        if retval != 0 {
            return None;
        }
        recv
    };
    // Mac OS X reports the maxrss in bytes, not kb.
    let divisor = if env::consts::OS == "macos" { 1024 } else { 1 };
    let maxrss = rusage.ru_maxrss + (divisor - 1) / divisor;

    let mut init_str = format!(
        "user: {USER_SEC}.{USER_USEC:03} \
         sys: {SYS_SEC}.{SYS_USEC:03} \
         max rss (kb): {MAXRSS}",
        USER_SEC = rusage.ru_utime.tv_sec,
        USER_USEC = rusage.ru_utime.tv_usec,
        SYS_SEC = rusage.ru_stime.tv_sec,
        SYS_USEC = rusage.ru_stime.tv_usec,
        MAXRSS = maxrss
    );

    // The remaining rusage stats vary in platform support. So we treat
    // uniformly zero values in each category as "not worth printing", since it
    // either means no events of that type occurred, or that the platform
    // does not support it.

    let minflt = rusage.ru_minflt;
    let majflt = rusage.ru_majflt;
    if minflt != 0 || majflt != 0 {
        init_str.push_str(&format!(" page reclaims: {} page faults: {}", minflt, majflt));
    }

    let inblock = rusage.ru_inblock;
    let oublock = rusage.ru_oublock;
    if inblock != 0 || oublock != 0 {
        init_str.push_str(&format!(" fs block inputs: {} fs block outputs: {}", inblock, oublock));
    }

    let nvcsw = rusage.ru_nvcsw;
    let nivcsw = rusage.ru_nivcsw;
    if nvcsw != 0 || nivcsw != 0 {
        init_str.push_str(&format!(
            " voluntary ctxt switches: {} involuntary ctxt switches: {}",
            nvcsw, nivcsw
        ));
    }

    return Some(init_str);
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use hir::{self, Docs, HasSource};
use ra_assists::utils::get_missing_impl_items;
use ra_syntax::{
    ast::{self, edit},
    AstNode, SyntaxKind, SyntaxNode, TextRange,
};
use ra_text_edit::TextEdit;

use crate::{
    completion::{
        CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
    },
    display::FunctionSignature,
};

pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
    let trigger = ctx.token.ancestors().find(|p| match p.kind() {
        SyntaxKind::FN_DEF | SyntaxKind::TYPE_ALIAS_DEF | SyntaxKind::CONST_DEF => true,
        _ => false,
    });

    let impl_block = trigger
        .as_ref()
        .and_then(|node| node.parent())
        .and_then(|node| node.parent())
        .and_then(|node| ast::ImplBlock::cast(node));

    if let (Some(trigger), Some(impl_block)) = (trigger, impl_block) {
        match trigger.kind() {
            SyntaxKind::FN_DEF => {
                for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
                    .iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::Function(fn_item) => Some(fn_item),
                        _ => None,
                    })
                {
                    add_function_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            SyntaxKind::TYPE_ALIAS_DEF => {
                for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
                    .iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::TypeAlias(type_item) => Some(type_item),
                        _ => None,
                    })
                {
                    add_type_alias_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            SyntaxKind::CONST_DEF => {
                for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
                    .iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::Const(const_item) => Some(const_item),
                        _ => None,
                    })
                {
                    add_const_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            _ => {}
        }
    }
}

fn add_function_impl(
    fn_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    func: &hir::Function,
) {
    let display = FunctionSignature::from_hir(ctx.db, func.clone());

    let fn_name = func.name(ctx.db).to_string();

    let label = if func.params(ctx.db).len() > 0 {
        format!("fn {}(..)", fn_name)
    } else {
        format!("fn {}()", fn_name)
    };

    let builder = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label.clone())
        .lookup_by(fn_name)
        .set_documentation(func.docs(ctx.db));

    let completion_kind = if func.has_self_param(ctx.db) {
        CompletionItemKind::Method
    } else {
        CompletionItemKind::Function
    };

    let snippet = format!("{} {{}}", display);

    builder
        .text_edit(TextEdit::replace(fn_def_node.text_range(), snippet))
        .kind(completion_kind)
        .add_to(acc);
}

fn add_type_alias_impl(
    type_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    type_alias: &hir::TypeAlias,
) {
    let alias_name = type_alias.name(ctx.db).to_string();

    let snippet = format!("type {} = ", alias_name);

    CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
        .text_edit(TextEdit::replace(type_def_node.text_range(), snippet))
        .lookup_by(alias_name)
        .kind(CompletionItemKind::TypeAlias)
        .set_documentation(type_alias.docs(ctx.db))
        .add_to(acc);
}

fn add_const_impl(
    const_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    const_: &hir::Const,
) {
    let const_name = const_.name(ctx.db).map(|n| n.to_string());

    if let Some(const_name) = const_name {
        let snippet = make_const_compl_syntax(&const_.source(ctx.db).value);

        CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
            .text_edit(TextEdit::replace(const_def_node.text_range(), snippet))
            .lookup_by(const_name)
            .kind(CompletionItemKind::Const)
            .set_documentation(const_.docs(ctx.db))
            .add_to(acc);
    }
}

fn make_const_compl_syntax(const_: &ast::ConstDef) -> String {
    let const_ = edit::strip_attrs_and_docs(const_);

    let const_start = const_.syntax().text_range().start();
    let const_end = const_.syntax().text_range().end();

    let start =
        const_.syntax().first_child_or_token().map_or(const_start, |f| f.text_range().start());

    let end = const_
        .syntax()
        .children_with_tokens()
        .find(|s| s.kind() == SyntaxKind::SEMI || s.kind() == SyntaxKind::EQ)
        .map_or(const_end, |f| f.text_range().start());

    let len = end - start;
    let range = TextRange::from_to(0.into(), len);

    let syntax = const_.syntax().text().slice(range).to_string();

    format!("{} = ", syntax.trim_end())
}

#[cfg(test)]
mod tests {
    use crate::completion::{do_completion, CompletionItem, CompletionKind};
    use insta::assert_debug_snapshot;

    fn complete(code: &str) -> Vec<CompletionItem> {
        do_completion(code, CompletionKind::Magic)
    }

    #[test]
    fn single_function() {
        let completions = complete(
            r"
            trait Test {
                fn foo();
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [141; 142),
                delete: [138; 142),
                insert: "fn foo() {}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn hide_implemented_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo();
                fn foo_bar();
            }

            struct T1;

            impl Test for T1 {
                fn foo() {}

                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo_bar()",
                source_range: [200; 201),
                delete: [197; 201),
                insert: "fn foo_bar() {}",
                kind: Function,
                lookup: "foo_bar",
            },
        ]
        "###);
    }

    #[test]
    fn generic_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo<T>();
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [144; 145),
                delete: [141; 145),
                insert: "fn foo<T>() {}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn generic_constrait_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo<T>() where T: Into<String>;
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [166; 167),
                delete: [163; 167),
                insert: "fn foo<T>()\nwhere T: Into<String> {}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn associated_type() {
        let completions = complete(
            r"
            trait Test {
                type SomeType;
            }

            impl Test for () {
                type S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "type SomeType = ",
                source_range: [124; 125),
                delete: [119; 125),
                insert: "type SomeType = ",
                kind: TypeAlias,
                lookup: "SomeType",
            },
        ]
        "###);
    }

    #[test]
    fn associated_const() {
        let completions = complete(
            r"
            trait Test {
                const SOME_CONST: u16;
            }

            impl Test for () {
                const S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const SOME_CONST: u16 = ",
                source_range: [133; 134),
                delete: [127; 134),
                insert: "const SOME_CONST: u16 = ",
                kind: Const,
                lookup: "SOME_CONST",
            },
        ]
        "###);
    }

    #[test]
    fn associated_const_with_default() {
        let completions = complete(
            r"
            trait Test {
                const SOME_CONST: u16 = 42;
            }

            impl Test for () {
                const S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const SOME_CONST: u16 = ",
                source_range: [138; 139),
                delete: [132; 139),
                insert: "const SOME_CONST: u16 = ",
                kind: Const,
                lookup: "SOME_CONST",
            },
        ]
        "###);
    }
}
<commit_msg>Fixed bug that allowed for completion in a nested method.<commit_after>//! FIXME: write short doc here

use hir::{self, Docs, HasSource};
use ra_assists::utils::get_missing_impl_items;
use ra_syntax::{
    ast::{self, edit},
    AstNode, SyntaxKind, SyntaxNode, TextRange,
};
use ra_text_edit::TextEdit;

use crate::{
    completion::{
        CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
    },
    display::FunctionSignature,
};

pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
    let trigger = ctx.token.ancestors().find(|p| match p.kind() {
        SyntaxKind::FN_DEF
        | SyntaxKind::TYPE_ALIAS_DEF
        | SyntaxKind::CONST_DEF
        | SyntaxKind::BLOCK_EXPR => true,
        _ => false,
    });

    let impl_block = trigger
        .as_ref()
        .and_then(|node| node.parent())
        .and_then(|node| node.parent())
        .and_then(|node| ast::ImplBlock::cast(node));

    if let (Some(trigger), Some(impl_block)) = (trigger, impl_block) {
        match trigger.kind() {
            SyntaxKind::FN_DEF => {
                for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
                    .iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::Function(fn_item) => Some(fn_item),
                        _ => None,
                    })
                {
                    add_function_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            SyntaxKind::TYPE_ALIAS_DEF => {
                for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
                    .iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::TypeAlias(type_item) => Some(type_item),
                        _ => None,
                    })
                {
                    add_type_alias_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            SyntaxKind::CONST_DEF => {
                for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
                    .iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::Const(const_item) => Some(const_item),
                        _ => None,
                    })
                {
                    add_const_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            _ => {}
        }
    }
}

fn add_function_impl(
    fn_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    func: &hir::Function,
) {
    let display = FunctionSignature::from_hir(ctx.db, func.clone());

    let fn_name = func.name(ctx.db).to_string();

    let label = if func.params(ctx.db).len() > 0 {
        format!("fn {}(..)", fn_name)
    } else {
        format!("fn {}()", fn_name)
    };

    let builder = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label.clone())
        .lookup_by(fn_name)
        .set_documentation(func.docs(ctx.db));

    let completion_kind = if func.has_self_param(ctx.db) {
        CompletionItemKind::Method
    } else {
        CompletionItemKind::Function
    };

    let snippet = format!("{} {{}}", display);

    let range = TextRange::from_to(fn_def_node.text_range().start(), ctx.source_range().end());

    builder.text_edit(TextEdit::replace(range, snippet)).kind(completion_kind).add_to(acc);
}

fn add_type_alias_impl(
    type_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    type_alias: &hir::TypeAlias,
) {
    let alias_name = type_alias.name(ctx.db).to_string();

    let snippet = format!("type {} = ", alias_name);

    let range = TextRange::from_to(type_def_node.text_range().start(), ctx.source_range().end());

    CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
        .text_edit(TextEdit::replace(range, snippet))
        .lookup_by(alias_name)
        .kind(CompletionItemKind::TypeAlias)
        .set_documentation(type_alias.docs(ctx.db))
        .add_to(acc);
}

fn add_const_impl(
    const_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    const_: &hir::Const,
) {
    let const_name = const_.name(ctx.db).map(|n| n.to_string());

    if let Some(const_name) = const_name {
        let snippet = make_const_compl_syntax(&const_.source(ctx.db).value);

        let range =
            TextRange::from_to(const_def_node.text_range().start(), ctx.source_range().end());

        CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
            .text_edit(TextEdit::replace(range, snippet))
            .lookup_by(const_name)
            .kind(CompletionItemKind::Const)
            .set_documentation(const_.docs(ctx.db))
            .add_to(acc);
    }
}

fn make_const_compl_syntax(const_: &ast::ConstDef) -> String {
    let const_ = edit::strip_attrs_and_docs(const_);

    let const_start = const_.syntax().text_range().start();
    let const_end = const_.syntax().text_range().end();

    let start =
        const_.syntax().first_child_or_token().map_or(const_start, |f| f.text_range().start());

    let end = const_
        .syntax()
        .children_with_tokens()
        .find(|s| s.kind() == SyntaxKind::SEMI || s.kind() == SyntaxKind::EQ)
        .map_or(const_end, |f| f.text_range().start());

    let len = end - start;
    let range = TextRange::from_to(0.into(), len);

    let syntax = const_.syntax().text().slice(range).to_string();

    format!("{} = ", syntax.trim_end())
}

#[cfg(test)]
mod tests {
    use crate::completion::{do_completion, CompletionItem, CompletionKind};
    use insta::assert_debug_snapshot;

    fn complete(code: &str) -> Vec<CompletionItem> {
        do_completion(code, CompletionKind::Magic)
    }

    #[test]
    fn single_function() {
        let completions = complete(
            r"
            trait Test {
                fn foo();
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [141; 142),
                delete: [138; 142),
                insert: "fn foo() {}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn hide_implemented_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo();
                fn foo_bar();
            }

            struct T1;

            impl Test for T1 {
                fn foo() {}

                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo_bar()",
                source_range: [200; 201),
                delete: [197; 201),
                insert: "fn foo_bar() {}",
                kind: Function,
                lookup: "foo_bar",
            },
        ]
        "###);
    }

    #[test]
    fn completes_only_on_top_level() {
        let completions = complete(
            r"
            trait Test {
                fn foo();

                fn foo_bar();
            }

            struct T1;

            impl Test for T1 {
                fn foo() {
                    <|>
                }
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"[]"###);
    }

    #[test]
    fn generic_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo<T>();
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [144; 145),
                delete: [141; 145),
                insert: "fn foo<T>() {}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn generic_constrait_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo<T>() where T: Into<String>;
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [166; 167),
                delete: [163; 167),
                insert: "fn foo<T>()\nwhere T: Into<String> {}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn associated_type() {
        let completions = complete(
            r"
            trait Test {
                type SomeType;
            }

            impl Test for () {
                type S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "type SomeType = ",
                source_range: [124; 125),
                delete: [119; 125),
                insert: "type SomeType = ",
                kind: TypeAlias,
                lookup: "SomeType",
            },
        ]
        "###);
    }

    #[test]
    fn associated_const() {
        let completions = complete(
            r"
            trait Test {
                const SOME_CONST: u16;
            }

            impl Test for () {
                const S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const SOME_CONST: u16 = ",
                source_range: [133; 134),
                delete: [127; 134),
                insert: "const SOME_CONST: u16 = ",
                kind: Const,
                lookup: "SOME_CONST",
            },
        ]
        "###);
    }

    #[test]
    fn associated_const_with_default() {
        let completions = complete(
            r"
            trait Test {
                const SOME_CONST: u16 = 42;
            }

            impl Test for () {
                const S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const SOME_CONST: u16 = ",
                source_range: [138; 139),
                delete: [132; 139),
                insert: "const SOME_CONST: u16 = ",
                kind: Const,
                lookup: "SOME_CONST",
            },
        ]
        "###);
    }
}
<|endoftext|>


<commit_before>/// Serial port management module supporting one
/// writer and multiple readers
///
/// Clients can lock a port for writing, but
/// subscribe to data from multiple ports for reads

use std::collections::HashSet;
use std::iter::FromIterator;
use std::sync::mpsc::{Receiver, TryRecvError};
use std::thread;
use std::time::{Duration, SystemTime};

use base64;

use serial_support::errors::*;
use serial_support::messages::*;
use serial_support::sub_manager::*;
use serial_support::port_manager::*;
use serial_support::writelock_manager::*;
use serial_support::common::*;

/// Manager manages connection state.
struct Manager {
  /// Manage write lock status
  writelock_manager: WriteLockManager,
  /// Manage ports
  port_manager: PortManager,
  /// Manage subscriptions
  sub_manager: SubscriptionManager,
  /// Receiver for serial requests
  receiver: Receiver<SerialRequest>,
  /// Receiver for response subscription requests
  subsc_receiver: SubscReceiver,
}

impl Manager {
  ///Constructor
  pub fn new(receiver: Receiver<SerialRequest>, subsc_receiver: SubscReceiver) -> Manager {
    Manager {
      writelock_manager: WriteLockManager::new(),
      port_manager: PortManager::new(),
      sub_manager: SubscriptionManager::new(),
      receiver: receiver,
      subsc_receiver: subsc_receiver,
    }
  }

  ///Spawn an instance in a new thread.
  pub fn spawn(receiver: Receiver<SerialRequest>,
               subsc_receiver: SubscReceiver)
               -> thread::JoinHandle<()> {
    thread::spawn(move || { Manager::new(receiver, subsc_receiver).run(); })
  }

  /// Main loop
  fn run(&mut self) {

    // Bad ports we couldn't read from
    // A set of SerialResponse::Errors built from
    // from the serial port read/write error responses
    let mut bad_ports = HashSet::<String>::new();
    // Shutdown flag
    let mut shutdown = false;
    // Check about 30 times a second
    let sleep_dur = Duration::from_millis(33);

    while !shutdown {
      // Sleep for a little bit to avoid pegging cpu
      // TODO Dynamic timing loop
      thread::sleep(sleep_dur);

      // Handle serial operation requests
      match self.receiver.try_recv() {
        Err(e) => {
          match e {
            TryRecvError::Empty => {
              // nothing to do
            }
            TryRecvError::Disconnected => {
              // Remote end hung up, time to shutdown
              info!("Shutting down SerialPortManager");
              shutdown = true;
            }
          }
        }
        Ok(req) => self.handle_serial_request(req),
      }

      // Check for new data on each port
      for (port_name, result) in self.port_manager.read_all_ports() {
        match result {
          Ok(data) => {
            let response = match String::from_utf8(data) {
              // We need to send as binary
              Err(e) => {
                SerialResponse::Read {
                  port: port_name.to_string(),
                  data: base64::encode(&e.into_bytes()),
                  base64: Some(true),
                }
              }
              Ok(s) => {
                SerialResponse::Read {
                  port: port_name.to_string(),
                  data: s,
                  base64: Some(false),
                }
              }
            };
            self.broadcast_message_for_port(&port_name, response);
          }
          // Send data reads
          Err(e) => {
            bad_ports.insert(port_name);
          }
        }
      }

      //Handle write requests
      let mut recv_count = 0;
      let mut do_recv = true;
      while do_recv {
        recv_count += 1;
        match self.subsc_receiver.try_recv() {
          Ok(sub_request) => self.sub_manager.add_subscription(sub_request),
          Err(e) => {
            match e {
              TryRecvError::Disconnected => {
                // Does this mean all senders have disconnected?
                // Or just one?
                debug!("Got disconnected when trying to get serial request");
              }
              TryRecvError::Empty => do_recv = false,
            }
          }
        }

        // Don't let this loop get stuck here forever
        // starving the outer loop
        if recv_count == 50 {
          do_recv = false;
        }
      }

      // Cleanup bad serial ports that failed read or write
      // We remove them from everything before
      self.cleanup_bad_ports(&bad_ports);
      bad_ports.clear();
    }
  }

  /// Handles and dispatches SerialRequest sent by
  /// the channel
  fn handle_serial_request(&mut self, msg: SerialRequest) {
    let response = match msg {
      SerialRequest::Open { sub_id, port } => self.handle_open_port(sub_id, port),
      SerialRequest::WriteLock { sub_id, port } => self.handle_write_lock(sub_id, port),
      SerialRequest::ReleaseWriteLock { sub_id, port } => {
        self.handle_release_write_lock(sub_id, port)
      }
      SerialRequest::Write {
        sub_id,
        port,
        data,
        base64,
      } => self.handle_write_port(sub_id, port, data, base64.unwrap_or(false)),
      SerialRequest::Close { sub_id, port } => self.handle_close_port(sub_id, port),
    };
    match response {
      Ok(response) => {}
      Err(e) => {}
    }
  }

  /// Handle write port requests
  fn handle_write_port(&self,
                       sub_id: String,
                       port_name: String,
                       data: String,
                       base_64: bool)
                       -> Result<SerialResponse> {
    self.check_sub_id(&sub_id)?;
    self.check_owns_writelock(&port_name, &sub_id)?;
    match base_64 {
      true => {
        base64::decode(&data)
          .map_err(|e| ErrorKind::Base64(e).into())
          .and_then(|d| self.port_manager.write_port(&port_name, &d))
          .and(Ok(SerialResponse::Ok { msg: "Write successful".to_string() }))
      }
      false => {
        self
          .port_manager
          .write_port(&port_name, data.as_bytes())
          .and(Ok(SerialResponse::Ok { msg: "Write successful".to_string() }))
      }
    }
  }

  /// Handle write lock requests
  fn handle_write_lock(&mut self, sub_id: String, port_name: String) -> Result<SerialResponse> {
    self.check_sub_id(&sub_id)?;
    self
      .writelock_manager
      .lock_port(&port_name, &sub_id)
      .and(Ok(SerialResponse::Ok {
                msg: format!("Locking port {} succeeded", port_name).to_string(),
              }))
  }

  /// Handle write requests
  fn handle_release_write_lock(&mut self,
                               sub_id: String,
                               port_name: Option<String>)
                               -> Result<SerialResponse> {
    match port_name {
      None => {
        self.writelock_manager.unlock_all_ports_for_sub(&sub_id);
        Ok(SerialResponse::Ok { msg: "Unlocking all ports locked by client succeeded".to_string() })
      }
      Some(port_name) => {
        self
          .writelock_manager
          .unlock_port(&port_name, &sub_id)
          .and(Ok(SerialResponse::Ok {
                    msg: format!("Locking port {} succeeded", port_name).to_string(),
                  }))
      }
    }
  }

  /// Handle open port requests
  fn handle_open_port(&mut self, sub_id: String, port_name: String) -> Result<SerialResponse> {
    self.check_sub_id(&sub_id)?;
    self.port_manager.open_port(&port_name)?;
    self
      .sub_manager
      .add_port(&sub_id, &port_name)
      .and(Ok(SerialResponse::Ok {
                msg: format!("Opening port {} succeeded", port_name).to_string(),
              }))
  }

  /// Handle close port requests
  fn handle_close_port(&mut self,
                       sub_id: String,
                       port_name: Option<String>)
                       -> Result<SerialResponse> {
    self.check_sub_id(&sub_id)?;
    // Unsubscribe from ports
    match port_name {
      None => self.sub_manager.clear_ports(Some(&sub_id)),
      Some(pn) => self.sub_manager.remove_port(&sub_id, &pn),
    }?;
    // Close ports with no subscribers
    let open_ports = HashSet::<String>::from_iter(self.port_manager.open_ports());
    let subscribed_ports = HashSet::<String>::from_iter(self.sub_manager.subscribed_ports());
    let ports_with_no_subs = open_ports.difference(&subscribed_ports);
    // For each open port that isn't subscribed,
    for port_to_close in ports_with_no_subs {
      // close it
      self.port_manager.close_port(&port_to_close);
      // remove the write lock
      self.writelock_manager.clear_lock(&port_to_close);
      // Let them know its closed
      let close_resp = SerialResponse::Closed { port: port_to_close.clone() };
      self.send_message(&sub_id, close_resp);
    }
    Ok(SerialResponse::Ok { msg: "Derp".to_string() })
  }

  /// Cleanup any bad ports
  /// Clears out the passed in hash set
  fn cleanup_bad_ports(&mut self, bad_ports: &HashSet<String>) {
    for port_name in bad_ports.iter() {
      // Tell everyone port is sick
      let err_resp = SerialResponse::Error {
        display: format!("Error reading from port '{}', closing!", port_name),
        description: format!("An error occured while trying to read data from '{}'",
                             port_name),
      };
      self.broadcast_message_for_port(port_name, err_resp);
      // Tesll everyone the sick ports were closed
      let close_resp = SerialResponse::Closed { port: port_name.clone() };
      self.broadcast_message_for_port(port_name, close_resp);
      // Close bad ports
      self.port_manager.close_port(port_name);
      // Remove write locks on bad ports
      self.writelock_manager.clear_lock(port_name);
      // Remove bad ports from subscriptions
      self.sub_manager.remove_port_from_all(port_name);
    }
    // Clear set of bad_ports
  }

  pub fn send_message(&mut self, sub_id: &String, msg: SerialResponse) {
    match self.sub_manager.send_message(sub_id, msg) {
      Err(e) => {
        let mut bad_subs = Vec::new();
        bad_subs.push(e);
        self.cleanup_bad_subs(bad_subs);
      }
      _ => {}
    }
  }

  /// Broadcast a message to all subscribers and
  /// then cleanup any subs that errored
  pub fn broadcast_message(&mut self, msg: SerialResponse) {
    let bad_subs = self.sub_manager.broadcast_message(msg);
    self.cleanup_bad_subs(bad_subs);
  }

  /// Broadcast a message to all subscribers interested in the
  /// given port and then cleanup any subs that errored
  pub fn broadcast_message_for_port(&mut self, port_name: &String, msg: SerialResponse) {
    let bad_subs = self
      .sub_manager
      .broadcast_message_for_port(port_name, msg);
    self.cleanup_bad_subs(bad_subs);
  }

  /// Cleanup any bad subs where a message send failed
  fn cleanup_bad_subs(&mut self, bad_subs: Vec<Error>) {
    for e in bad_subs {
      match e {
        Error(ErrorKind::SubscriberSendError(sub_id), _) => {
          self.sub_manager.end_subscription(&sub_id);
          self.writelock_manager.unlock_all_ports_for_sub(&sub_id);
        }
        _ => { /*nop*/ }
      }
    }
  }

  fn check_sub_id(&self, sub_id: &String) -> Result<()> {
    self.sub_manager.check_subscription_exists(sub_id)
  }

  fn check_owns_writelock(&self, port_name: &String, sub_id: &String) -> Result<()> {
    self
      .writelock_manager
      .check_owns_write_lock(port_name, sub_id)
  }
}
<commit_msg>When port read fails, log the error<commit_after>/// Serial port management module supporting one
/// writer and multiple readers
///
/// Clients can lock a port for writing, but
/// subscribe to data from multiple ports for reads

use std::collections::HashSet;
use std::iter::FromIterator;
use std::sync::mpsc::{Receiver, TryRecvError};
use std::thread;
use std::time::{Duration, SystemTime};

use base64;

use serial_support::errors::*;
use serial_support::messages::*;
use serial_support::sub_manager::*;
use serial_support::port_manager::*;
use serial_support::writelock_manager::*;
use serial_support::common::*;

/// Manager manages connection state.
/// TODO Needs a better name
pub struct Manager {
  /// Manage write lock status
  writelock_manager: WriteLockManager,
  /// Manage ports
  port_manager: PortManager,
  /// Manage subscriptions
  sub_manager: SubscriptionManager,
  /// Receiver for serial requests
  receiver: Receiver<SerialRequest>,
  /// Receiver for response subscription requests
  subsc_receiver: SubscReceiver,
}

impl Manager {
  ///Constructor
  pub fn new(receiver: Receiver<SerialRequest>, subsc_receiver: SubscReceiver) -> Manager {
    Manager {
      writelock_manager: WriteLockManager::new(),
      port_manager: PortManager::new(),
      sub_manager: SubscriptionManager::new(),
      receiver: receiver,
      subsc_receiver: subsc_receiver,
    }
  }

  ///Spawn an instance in a new thread.
  pub fn spawn(receiver: Receiver<SerialRequest>,
               subsc_receiver: SubscReceiver)
               -> thread::JoinHandle<()> {
    thread::spawn(move || { Manager::new(receiver, subsc_receiver).run(); })
  }

  /// Main loop
  fn run(&mut self) {

    // Bad ports we couldn't read from
    // A set of SerialResponse::Errors built from
    // from the serial port read/write error responses
    let mut bad_ports = HashSet::<String>::new();
    // Shutdown flag
    let mut shutdown = false;
    // Check about 30 times a second
    let sleep_dur = Duration::from_millis(33);

    while !shutdown {
      // Sleep for a little bit to avoid pegging cpu
      // TODO Dynamic timing loop
      thread::sleep(sleep_dur);

      // Handle serial operation requests
      match self.receiver.try_recv() {
        Err(e) => {
          match e {
            TryRecvError::Empty => {
              // nothing to do
            }
            TryRecvError::Disconnected => {
              // Remote end hung up, time to shutdown
              info!("Shutting down SerialPortManager");
              shutdown = true;
            }
          }
        }
        Ok(req) => self.handle_serial_request(req),
      }

      // Check for new data on each port
      for (port_name, result) in self.port_manager.read_all_ports() {
        match result {
          Ok(data) => {
            let response = match String::from_utf8(data) {
              // We need to send as binary
              Err(e) => {
                SerialResponse::Read {
                  port: port_name.to_string(),
                  data: base64::encode(&e.into_bytes()),
                  base64: Some(true),
                }
              }
              Ok(s) => {
                SerialResponse::Read {
                  port: port_name.to_string(),
                  data: s,
                  base64: Some(false),
                }
              }
            };
            self.broadcast_message_for_port(&port_name, response);
          }
          // Send data reads
          Err(e) => {
            warn!("Error reading port!");
            warn!("{}",e);
            bad_ports.insert(port_name);
          }
        }
      }

      //Handle write requests
      let mut recv_count = 0;
      let mut do_recv = true;
      while do_recv {
        recv_count += 1;
        match self.subsc_receiver.try_recv() {
          Ok(sub_request) => self.sub_manager.add_subscription(sub_request),
          Err(e) => {
            match e {
              TryRecvError::Disconnected => {
                // Does this mean all senders have disconnected?
                // Or just one?
                debug!("Got disconnected when trying to get serial request");
              }
              TryRecvError::Empty => do_recv = false,
            }
          }
        }

        // Don't let this loop get stuck here forever
        // starving the outer loop
        if recv_count == 50 {
          do_recv = false;
        }
      }

      // Cleanup bad serial ports that failed read or write
      // We remove them from everything before
      self.cleanup_bad_ports(&bad_ports);
      bad_ports.clear();
    }
  }

  /// Handles and dispatches SerialRequest sent by
  /// the channel
  fn handle_serial_request(&mut self, msg: SerialRequest) {
    let response = match msg {
      SerialRequest::Open { sub_id, port } => self.handle_open_port(sub_id, port),
      SerialRequest::WriteLock { sub_id, port } => self.handle_write_lock(sub_id, port),
      SerialRequest::ReleaseWriteLock { sub_id, port } => {
        self.handle_release_write_lock(sub_id, port)
      }
      SerialRequest::Write {
        sub_id,
        port,
        data,
        base64,
      } => self.handle_write_port(sub_id, port, data, base64.unwrap_or(false)),
      SerialRequest::Close { sub_id, port } => self.handle_close_port(sub_id, port),
    };
    match response {
      Ok(response) => {}
      Err(e) => {}
    }
  }

  /// Handle write port requests
  fn handle_write_port(&self,
                       sub_id: String,
                       port_name: String,
                       data: String,
                       base_64: bool)
                       -> Result<SerialResponse> {
    self.check_sub_id(&sub_id)?;
    self.check_owns_writelock(&port_name, &sub_id)?;
    match base_64 {
      true => {
        base64::decode(&data)
          .map_err(|e| ErrorKind::Base64(e).into())
          .and_then(|d| self.port_manager.write_port(&port_name, &d))
          .and(Ok(SerialResponse::Ok { msg: "Write successful".to_string() }))
      }
      false => {
        self
          .port_manager
          .write_port(&port_name, data.as_bytes())
          .and(Ok(SerialResponse::Ok { msg: "Write successful".to_string() }))
      }
    }
  }

  /// Handle write lock requests
  fn handle_write_lock(&mut self, sub_id: String, port_name: String) -> Result<SerialResponse> {
    self.check_sub_id(&sub_id)?;
    self
      .writelock_manager
      .lock_port(&port_name, &sub_id)
      .and(Ok(SerialResponse::Ok {
                msg: format!("Locking port {} succeeded", port_name).to_string(),
              }))
  }

  /// Handle write requests
  fn handle_release_write_lock(&mut self,
                               sub_id: String,
                               port_name: Option<String>)
                               -> Result<SerialResponse> {
    match port_name {
      None => {
        self.writelock_manager.unlock_all_ports_for_sub(&sub_id);
        Ok(SerialResponse::Ok { msg: "Unlocking all ports locked by client succeeded".to_string() })
      }
      Some(port_name) => {
        self
          .writelock_manager
          .unlock_port(&port_name, &sub_id)
          .and(Ok(SerialResponse::Ok {
                    msg: format!("Locking port {} succeeded", port_name).to_string(),
                  }))
      }
    }
  }

  /// Handle open port requests
  fn handle_open_port(&mut self, sub_id: String, port_name: String) -> Result<SerialResponse> {
    self.check_sub_id(&sub_id)?;
    self.port_manager.open_port(&port_name)?;
    self
      .sub_manager
      .add_port(&sub_id, &port_name)
      .and(Ok(SerialResponse::Ok {
                msg: format!("Opening port {} succeeded", port_name).to_string(),
              }))
  }

  /// Handle close port requests
  fn handle_close_port(&mut self,
                       sub_id: String,
                       port_name: Option<String>)
                       -> Result<SerialResponse> {
    self.check_sub_id(&sub_id)?;
    // Unsubscribe from ports
    match port_name {
      None => self.sub_manager.clear_ports(Some(&sub_id)),
      Some(pn) => self.sub_manager.remove_port(&sub_id, &pn),
    }?;
    // Close ports with no subscribers
    let open_ports = HashSet::<String>::from_iter(self.port_manager.open_ports());
    let subscribed_ports = HashSet::<String>::from_iter(self.sub_manager.subscribed_ports());
    let ports_with_no_subs = open_ports.difference(&subscribed_ports);
    // For each open port that isn't subscribed,
    for port_to_close in ports_with_no_subs {
      // close it
      self.port_manager.close_port(&port_to_close);
      // remove the write lock
      self.writelock_manager.clear_lock(&port_to_close);
      // Let them know its closed
      let close_resp = SerialResponse::Closed { port: port_to_close.clone() };
      self.send_message(&sub_id, close_resp);
    }
    Ok(SerialResponse::Ok { msg: "Derp".to_string() })
  }

  /// Cleanup any bad ports
  /// Clears out the passed in hash set
  fn cleanup_bad_ports(&mut self, bad_ports: &HashSet<String>) {
    for port_name in bad_ports.iter() {
      // Tell everyone port is sick
      let err_resp = SerialResponse::Error {
        display: format!("Error reading from port '{}', closing!", port_name),
        description: format!("An error occured while trying to read data from '{}'",
                             port_name),
      };
      self.broadcast_message_for_port(port_name, err_resp);
      // Tesll everyone the sick ports were closed
      let close_resp = SerialResponse::Closed { port: port_name.clone() };
      self.broadcast_message_for_port(port_name, close_resp);
      // Close bad ports
      self.port_manager.close_port(port_name);
      // Remove write locks on bad ports
      self.writelock_manager.clear_lock(port_name);
      // Remove bad ports from subscriptions
      self.sub_manager.remove_port_from_all(port_name);
    }
    // Clear set of bad_ports
  }

  pub fn send_message(&mut self, sub_id: &String, msg: SerialResponse) {
    match self.sub_manager.send_message(sub_id, msg) {
      Err(e) => {
        let mut bad_subs = Vec::new();
        bad_subs.push(e);
        self.cleanup_bad_subs(bad_subs);
      }
      _ => {}
    }
  }

  /// Broadcast a message to all subscribers and
  /// then cleanup any subs that errored
  pub fn broadcast_message(&mut self, msg: SerialResponse) {
    let bad_subs = self.sub_manager.broadcast_message(msg);
    self.cleanup_bad_subs(bad_subs);
  }

  /// Broadcast a message to all subscribers interested in the
  /// given port and then cleanup any subs that errored
  pub fn broadcast_message_for_port(&mut self, port_name: &String, msg: SerialResponse) {
    let bad_subs = self
      .sub_manager
      .broadcast_message_for_port(port_name, msg);
    self.cleanup_bad_subs(bad_subs);
  }

  /// Cleanup any bad subs where a message send failed
  fn cleanup_bad_subs(&mut self, bad_subs: Vec<Error>) {
    for e in bad_subs {
      match e {
        Error(ErrorKind::SubscriberSendError(sub_id), _) => {
          self.sub_manager.end_subscription(&sub_id);
          self.writelock_manager.unlock_all_ports_for_sub(&sub_id);
        }
        _ => { /*nop*/ }
      }
    }
  }

  fn check_sub_id(&self, sub_id: &String) -> Result<()> {
    self.sub_manager.check_subscription_exists(sub_id)
  }

  fn check_owns_writelock(&self, port_name: &String, sub_id: &String) -> Result<()> {
    self
      .writelock_manager
      .check_owns_write_lock(port_name, sub_id)
  }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fs;
use std::path::Path;

use package::find;
use operation::selection;
use paths::{ self, PathAppend };

pub fn uninstall(input: &str, base_path: &Path) -> Result<bool, String> {
    let package_list_dir = get!(fs::read_dir(base_path.to_path_buf().append(paths::PACKAGE_LIST_DIR)), "");
    for list_path in package_list_dir {
        let result = try!(find::select_package(input, list_path.unwrap().path().as_path(), selection::select_package));
        let installation_path = base_path.to_path_buf().append(&(paths::PACKAGE_INSTALL_DIR.to_string() + &result.name + "/"));
        if installation_path.exists() {
            match fs::remove_dir_all(&installation_path) {
                Ok(x) => x,
                Err(why) => return Err(why.description().to_string())
            }
            return Ok(true)
        } else {
            continue;
        }
    }
    return Ok(false);
}
<commit_msg>Split the function into two.<commit_after>use std::error::Error;
use std::fs;
use std::path::Path;

use package::{ find, version };
use operation::selection;
use paths::{ self, PathAppend };

fn uninstall_package(input: Package, base_path: &Path) -> Result<bool, String> {
    let installation_path = base_path.to_path_buf().append(&(paths::PACKAGE_INSTALL_DIR.to_string() + &input.name + "/"));
    if installation_path.exists() {
        match fs::remove_dir_all(&installation_path) {
            Ok(x) => x,
            Err(why) => return Err(why.description().to_string())
        }
        return Ok(true)
    }
    return Ok(false);
}

pub fn uninstall(input: &str, base_path: &Path) -> Result<bool, String> {
    let package_list_dir = get!(fs::read_dir(base_path.to_path_buf().append(paths::PACKAGE_LIST_DIR)), "");
    for list_path in package_list_dir {
        let result = find::select_package(input, list_path.unwrap().path().as_path(), select_package);
        if result.is_ok() {
            let result = result.unwrap();
            return install_package(&result, base_path)
        }
    }
    Err("Specified package not found".to_string())
}<|endoftext|>


<commit_before>use std::{
    fs, io,
    path::{Path, PathBuf},
    sync::atomic::{AtomicUsize, Ordering},
};

pub(crate) struct TestDir {
    path: PathBuf,
    keep: bool,
}

impl TestDir {
    pub(crate) fn new() -> TestDir {
        let base = std::env::temp_dir().join("testdir");
        let pid = std::process::id();

        static CNT: AtomicUsize = AtomicUsize::new(0);
        for _ in 0..100 {
            let cnt = CNT.fetch_add(1, Ordering::Relaxed);
            let path = base.join(format!("{}_{}", pid, cnt));
            if path.is_dir() {
                continue;
            }
            fs::create_dir_all(&path).unwrap();
            return TestDir { path, keep: false };
        }
        panic!("Failed to create a temporary directory")
    }
    #[allow(unused)]
    pub(crate) fn keep(mut self) -> TestDir {
        self.keep = true;
        self
    }
    pub(crate) fn path(&self) -> &Path {
        &self.path
    }
}

impl Drop for TestDir {
    fn drop(&mut self) {
        if self.keep {
            return;
        }
        remove_dir_all(&self.path).unwrap()
    }
}

#[cfg(not(windows))]
fn remove_dir_all(path: &Path) -> io::Result<()> {
    fs::remove_dir_all(path)
}

#[cfg(windows)]
fn remove_dir_all(path: &Path) -> io::Result<()> {
    for _ in 0..99 {
        if fs::remove_dir_all(path).is_ok() {
            return Ok(());
        }
        std::thread::sleep(std::time::Duration::from_millis(10))
    }
    fs::remove_dir_all(path)
}
<commit_msg>fix tests<commit_after>use std::{
    fs, io,
    path::{Path, PathBuf},
    sync::atomic::{AtomicUsize, Ordering},
};

pub(crate) struct TestDir {
    path: PathBuf,
    keep: bool,
}

impl TestDir {
    pub(crate) fn new() -> TestDir {
        let temp_dir = std::env::temp_dir();
        // On MacOS builders on GitHub actions, the temp dir is a symlink, and
        // that causes problems down the line. Specifically:
        // * Cargo may emit different PackageId depending on the working directory
        // * rust-analyzer may fail to map LSP URIs to correct paths.
        //
        // Work-around this by canonicalizing. Note that we don't want to do this
        // on *every* OS, as on windows `canonicalize` itself creates problems.
        #[cfg(target_os = "macos")]
        let temp_dir = temp_dir.canonicalize().unwrap();

        let base = temp_dir.join("testdir");
        let pid = std::process::id();

        static CNT: AtomicUsize = AtomicUsize::new(0);
        for _ in 0..100 {
            let cnt = CNT.fetch_add(1, Ordering::Relaxed);
            let path = base.join(format!("{}_{}", pid, cnt));
            if path.is_dir() {
                continue;
            }
            fs::create_dir_all(&path).unwrap();
            return TestDir { path, keep: false };
        }
        panic!("Failed to create a temporary directory")
    }
    #[allow(unused)]
    pub(crate) fn keep(mut self) -> TestDir {
        self.keep = true;
        self
    }
    pub(crate) fn path(&self) -> &Path {
        &self.path
    }
}

impl Drop for TestDir {
    fn drop(&mut self) {
        if self.keep {
            return;
        }
        remove_dir_all(&self.path).unwrap()
    }
}

#[cfg(not(windows))]
fn remove_dir_all(path: &Path) -> io::Result<()> {
    fs::remove_dir_all(path)
}

#[cfg(windows)]
fn remove_dir_all(path: &Path) -> io::Result<()> {
    for _ in 0..99 {
        if fs::remove_dir_all(path).is_ok() {
            return Ok(());
        }
        std::thread::sleep(std::time::Duration::from_millis(10))
    }
    fs::remove_dir_all(path)
}
<|endoftext|>


<commit_before>#![feature(convert)]

extern crate pkg_config;

use std::io::ErrorKind;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

fn main() {
    register_dep("SSH2");
    register_dep("OPENSSL");

    let mut cflags = env::var("CFLAGS").unwrap_or(String::new());
    let target = env::var("TARGET").unwrap();
    let mingw = target.contains("windows-gnu");
    cflags.push_str(" -ffunction-sections -fdata-sections");

    if target.contains("i686") {
        cflags.push_str(" -m32");
    } else if target.contains("x86_64") {
        cflags.push_str(" -m64");
    }
    if !target.contains("i686") {
        cflags.push_str(" -fPIC");
    }

    let src = PathBuf::from(&env::var("CARGO_MANIFEST_DIR").unwrap());
    let dst = PathBuf::from(&env::var("OUT_DIR").unwrap());
    let _ = fs::create_dir(&dst.join("build"));

    let mut cmd = Command::new("cmake");
    cmd.arg(&src.join("libgit2"))
       .current_dir(&dst.join("build"));
    if mingw {
        cmd.arg("-G").arg("Unix Makefiles");
    }
    let profile = match &env::var("PROFILE").unwrap()[..] {
        "bench" | "release" => "Release",
        _ => "Debug",
    };
    run(cmd.arg("-DTHREADSAFE=ON")
           .arg("-DBUILD_SHARED_LIBS=OFF")
           .arg("-DBUILD_CLAR=OFF")
           .arg(&format!("-DCMAKE_BUILD_TYPE={}", profile))
           .arg(&format!("-DCMAKE_INSTALL_PREFIX={}", dst.display()))
           .arg("-DBUILD_EXAMPLES=OFF")
           .arg(&format!("-DCMAKE_C_FLAGS={}", cflags)), "cmake");
    run(Command::new("cmake")
                .arg("--build").arg(".")
                .arg("--target").arg("install")
                .current_dir(&dst.join("build")), "cmake");

    println!("cargo:root={}", dst.display());
    if mingw || target.contains("windows") {
        println!("cargo:rustc-flags=-l winhttp -l rpcrt4 -l ole32 \
                                    -l ws2_32 -l bcrypt -l crypt32 \
                                    -l git2:static -L {}",
                 dst.join("lib").display());
        return
    }

    if env::var("HOST") == env::var("TARGET") {
        append("PKG_CONFIG_PATH", dst.join("lib/pkgconfig"));
        if pkg_config::Config::new().statik(true).find("libgit2").is_ok() {
            return
        }
    }

    println!("cargo:rustc-flags=-l git2:static");
    println!("cargo:rustc-flags=-L {}", dst.join("lib").display());
    if target.contains("apple") {
        println!("cargo:rustc-flags=-l iconv");
    }
}

fn run(cmd: &mut Command, program: &str) {
    println!("running: {:?}", cmd);
    let status = match cmd.status() {
        Ok(status) => status,
        Err(ref e) if e.kind() == ErrorKind::NotFound => {
            fail(&format!("failed to execute command: {}\nis `{}` not installed?",
                          e, program));
        }
        Err(e) => fail(&format!("failed to execute command: {}", e)),
    };
    if !status.success() {
        fail(&format!("command did not execute successfully, got: {}", status));
    }
}

fn register_dep(dep: &str) {
    match env::var(&format!("DEP_{}_ROOT", dep)) {
        Ok(s) => {
            append("CMAKE_PREFIX_PATH", PathBuf::from(&s));
            append("PKG_CONFIG_PATH", Path::new(&s).join("lib/pkgconfig"));
        }
        Err(..) => {}
    }
}

fn append(var: &str, val: PathBuf) {
    let prefix = env::var(var).unwrap_or(String::new());
    let val = env::join_paths(env::split_paths(&prefix)
                                  .chain(Some(val).into_iter())).unwrap();
    env::set_var(var, &val);
}

fn fail(s: &str) -> ! {
    panic!("\n{}\n\nbuild script failed, must exit now", s)
}
<commit_msg>Use more modern link syntax on windows<commit_after>#![feature(convert)]

extern crate pkg_config;

use std::io::ErrorKind;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

fn main() {
    register_dep("SSH2");
    register_dep("OPENSSL");

    let mut cflags = env::var("CFLAGS").unwrap_or(String::new());
    let target = env::var("TARGET").unwrap();
    let mingw = target.contains("windows-gnu");
    cflags.push_str(" -ffunction-sections -fdata-sections");

    if target.contains("i686") {
        cflags.push_str(" -m32");
    } else if target.contains("x86_64") {
        cflags.push_str(" -m64");
    }
    if !target.contains("i686") {
        cflags.push_str(" -fPIC");
    }

    let src = PathBuf::from(&env::var("CARGO_MANIFEST_DIR").unwrap());
    let dst = PathBuf::from(&env::var("OUT_DIR").unwrap());
    let _ = fs::create_dir(&dst.join("build"));

    let mut cmd = Command::new("cmake");
    cmd.arg(&src.join("libgit2"))
       .current_dir(&dst.join("build"));
    if mingw {
        cmd.arg("-G").arg("Unix Makefiles");
    }
    let profile = match &env::var("PROFILE").unwrap()[..] {
        "bench" | "release" => "Release",
        _ => "Debug",
    };
    run(cmd.arg("-DTHREADSAFE=ON")
           .arg("-DBUILD_SHARED_LIBS=OFF")
           .arg("-DBUILD_CLAR=OFF")
           .arg(&format!("-DCMAKE_BUILD_TYPE={}", profile))
           .arg(&format!("-DCMAKE_INSTALL_PREFIX={}", dst.display()))
           .arg("-DBUILD_EXAMPLES=OFF")
           .arg(&format!("-DCMAKE_C_FLAGS={}", cflags)), "cmake");
    run(Command::new("cmake")
                .arg("--build").arg(".")
                .arg("--target").arg("install")
                .current_dir(&dst.join("build")), "cmake");

    println!("cargo:root={}", dst.display());
    if mingw || target.contains("windows") {
        println!("cargo:rustc-flags=-l winhttp -l rpcrt4 -l ole32 \
                                    -l ws2_32 -l bcrypt -l crypt32 \
                                    -l static=git2");
        println!("cargo:rustc-link-search=native={}/lib", dst.display());
        return
    }

    if env::var("HOST") == env::var("TARGET") {
        append("PKG_CONFIG_PATH", dst.join("lib/pkgconfig"));
        if pkg_config::Config::new().statik(true).find("libgit2").is_ok() {
            return
        }
    }

    println!("cargo:rustc-flags=-l git2:static");
    println!("cargo:rustc-flags=-L {}", dst.join("lib").display());
    if target.contains("apple") {
        println!("cargo:rustc-flags=-l iconv");
    }
}

fn run(cmd: &mut Command, program: &str) {
    println!("running: {:?}", cmd);
    let status = match cmd.status() {
        Ok(status) => status,
        Err(ref e) if e.kind() == ErrorKind::NotFound => {
            fail(&format!("failed to execute command: {}\nis `{}` not installed?",
                          e, program));
        }
        Err(e) => fail(&format!("failed to execute command: {}", e)),
    };
    if !status.success() {
        fail(&format!("command did not execute successfully, got: {}", status));
    }
}

fn register_dep(dep: &str) {
    match env::var(&format!("DEP_{}_ROOT", dep)) {
        Ok(s) => {
            append("CMAKE_PREFIX_PATH", PathBuf::from(&s));
            append("PKG_CONFIG_PATH", Path::new(&s).join("lib/pkgconfig"));
        }
        Err(..) => {}
    }
}

fn append(var: &str, val: PathBuf) {
    let prefix = env::var(var).unwrap_or(String::new());
    let val = env::join_paths(env::split_paths(&prefix)
                                  .chain(Some(val).into_iter())).unwrap();
    env::set_var(var, &val);
}

fn fail(s: &str) -> ! {
    panic!("\n{}\n\nbuild script failed, must exit now", s)
}
<|endoftext|>


<commit_before>use regex::{Captures, Regex};
use analysis::namespaces::MAIN;
use env::Env;

const LANGUAGE_SEP_BEGIN : &'static str = "<!-- language=\"";
const LANGUAGE_SEP_END : &'static str = "\" -->";
const LANGUAGE_BLOCK_BEGIN : &'static str = "|[";
const LANGUAGE_BLOCK_END : &'static str = "\n]|";

pub fn reformat_doc(input: &str, env: &Env) -> String {
    code_blocks_transformation(input, env)
}

fn try_split<'a>(src: &'a str, needle: &str) -> (&'a str, Option<&'a str>) {
    match src.find(needle) {
        Some(pos) => (&src[..pos], Some(&src[pos + needle.len()..])),
        None => (src, None),
    }
}

fn code_blocks_transformation(mut input: &str,
                              env: &Env) -> String {
    let mut out = String::new();

    loop {
        input = match try_split(input, LANGUAGE_BLOCK_BEGIN) {
            (before, Some(after)) => {
                out.push_str(&replace_c_types(before, env));
                if let (before, Some(after)) = try_split(get_language(after, &mut out),
                                                         LANGUAGE_BLOCK_END) {
                    out.push_str(before);
                    out.push_str("\n```");
                    after
                } else {
                    after
                }
            }
            (before, None) => {
                out.push_str(&replace_c_types(before, env));
                return out
            }
        };
    }
}

fn get_language<'a>(entry: &'a str, out: &mut String) -> &'a str {
    if let (_, Some(after)) = try_split(entry, LANGUAGE_SEP_BEGIN) {
        if let (before, Some(after)) = try_split(after, LANGUAGE_SEP_END) {
            out.push_str(&format!("```{}", before));
            return after
        }
    }
    out.push_str("```text");
    entry
}

lazy_static! {
    static ref REG : Regex = Regex::new(r"#?(G[dt]k)([\w]+:?:?\.?[\w-]+)").unwrap();
    static ref REG2 : Regex = Regex::new(r"@(\w*)").unwrap();
}

fn replace_c_types(entry: &str, env: &Env) -> String {
    let out = &REG.replace_all(entry, |caps: &Captures| {
        let pos = env.library.find_namespace(&caps[1]).unwrap();
        if pos == MAIN {
            format!("`{}`", &caps[2])
        } else {
            format!("`{}::{}`", &env.namespaces[pos].crate_name, &caps[2])
        }
    });
    REG2.replace_all(out, "`$1`")
}
<commit_msg>Delimit code blocks with newlines<commit_after>use regex::{Captures, Regex};
use analysis::namespaces::MAIN;
use env::Env;

const LANGUAGE_SEP_BEGIN : &'static str = "<!-- language=\"";
const LANGUAGE_SEP_END : &'static str = "\" -->";
const LANGUAGE_BLOCK_BEGIN : &'static str = "|[";
const LANGUAGE_BLOCK_END : &'static str = "\n]|";

pub fn reformat_doc(input: &str, env: &Env) -> String {
    code_blocks_transformation(input, env)
}

fn try_split<'a>(src: &'a str, needle: &str) -> (&'a str, Option<&'a str>) {
    match src.find(needle) {
        Some(pos) => (&src[..pos], Some(&src[pos + needle.len()..])),
        None => (src, None),
    }
}

fn code_blocks_transformation(mut input: &str,
                              env: &Env) -> String {
    let mut out = String::new();

    loop {
        input = match try_split(input, LANGUAGE_BLOCK_BEGIN) {
            (before, Some(after)) => {
                out.push_str(&replace_c_types(before, env));
                if let (before, Some(after)) = try_split(get_language(after, &mut out),
                                                         LANGUAGE_BLOCK_END) {
                    out.push_str(before);
                    out.push_str("\n```");
                    after
                } else {
                    after
                }
            }
            (before, None) => {
                out.push_str(&replace_c_types(before, env));
                return out
            }
        };
    }
}

fn get_language<'a>(entry: &'a str, out: &mut String) -> &'a str {
    if let (_, Some(after)) = try_split(entry, LANGUAGE_SEP_BEGIN) {
        if let (before, Some(after)) = try_split(after, LANGUAGE_SEP_END) {
            out.push_str(&format!("\n```{}", before));
            return after
        }
    }
    out.push_str("\n```text");
    entry
}

lazy_static! {
    static ref REG : Regex = Regex::new(r"#?(G[dt]k)([\w]+:?:?\.?[\w-]+)").unwrap();
    static ref REG2 : Regex = Regex::new(r"@(\w*)").unwrap();
}

fn replace_c_types(entry: &str, env: &Env) -> String {
    let out = &REG.replace_all(entry, |caps: &Captures| {
        let pos = env.library.find_namespace(&caps[1]).unwrap();
        if pos == MAIN {
            format!("`{}`", &caps[2])
        } else {
            format!("`{}::{}`", &env.namespaces[pos].crate_name, &caps[2])
        }
    });
    REG2.replace_all(out, "`$1`")
}
<|endoftext|>


<commit_before>use super::managed_display::ManagedDisplay;
use entities::{ EntitiesState, EntitiesHelper, EntityID, ComponentID, NativeComponentType };
use nalgebra::na;
use nalgebra::na::{ Vec3, Eye };
use std::collections::{ HashSet, HashMap };
use std::sync::Arc;
use super::sprite_displayer::SpriteDisplayer;
use super::Drawable;

mod custom_display_system;

pub struct DisplaySystem {
	display: Arc<ManagedDisplay>,
	customDisplay: custom_display_system::CustomDisplaySystem,
	sprites: HashMap<ComponentID, (Option<SpriteDisplayer>, String)>,
	logger: Box<::log::Logger>
}

impl DisplaySystem {
	pub fn new<L: ::log::Logger + 'static>(display: Arc<ManagedDisplay>, state: &EntitiesState, mut logger: L)
		-> DisplaySystem
	{
		declmagic_info!(logger, "created display system");

		DisplaySystem {
			display: display.clone(),
			customDisplay: custom_display_system::CustomDisplaySystem::new(display.clone(), state, logger.clone()),
			sprites: HashMap::new(),
			logger: box logger
		}
	}

	pub fn draw(&mut self, state: &EntitiesState, _: &f64)
	{
		self.update_sprite_displayers(state);

		let camera = DisplaySystem::get_camera(state).unwrap_or_else(|| {
			declmagic_warn!(self.logger, "no active camera on the scene");
			Eye::new_identity(4)
		});

	 	for (cmp, &(ref sprite, _)) in self.sprites.iter() {
	 		let pos = ::physics::PhysicsSystem::get_entity_position(state, &state.get_owner(cmp).unwrap());
	 		let translationMatrix = na::Mat4::new(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, pos.x, pos.y, pos.z, 1.0);
			sprite.as_ref().map(|e| e.draw(&(translationMatrix * camera)));
		}

		self.customDisplay.draw(state);
	}

	fn update_sprite_displayers(&mut self, state: &EntitiesState)
	{
		// getting the list of all sprite displayer components
		let listOfComponents = state
			.get_visible_native_components("spriteDisplay").move_iter()
			.collect::<HashSet<ComponentID>>();

		// removing from the list the elements that have disappeared
		{	let toRemove = self.sprites.keys().filter(|e| !listOfComponents.contains(e.clone())).map(|e| e.clone()).collect::<Vec<ComponentID>>();
			for c in toRemove.move_iter() {
				self.sprites.remove(&c);
			}
		}

		// adding elements that are not yet created
		{	let toCreate = listOfComponents.iter().filter(|e| !self.sprites.contains_key(e.clone())).map(|e| e.clone()).collect::<Vec<ComponentID>>();
			for spriteDisplayComponent in toCreate.move_iter() {
				// inserting in sprites list
				self.sprites.insert(spriteDisplayComponent.clone(), (None, format!("")));
			}
		}

		// updating everything
		for (component, &(ref mut sprite, ref mut currTexName)) in self.sprites.mut_iter() {
			// getting the name of the texture
			let textureName = match state.get_as_string(component, "texture") {
				Some(s) => s,
				_ => {
					// TODO:
					//declmagic_error!(self.logger, "component {} has no valid \"texture\" element", component)
					continue
				}
			};

			if sprite.is_none() || currTexName.as_slice() != textureName.as_slice() {
				(*sprite) = Some(SpriteDisplayer::new(self.display.clone(), textureName.as_slice()).unwrap());
				*currTexName = textureName;
			}

			// getting coordinates
			match sprite {
				&Some(ref mut s) =>
					s.set_rectangle_coords(
						state.get_as_number(component, "leftX").map(|n| n as f32),
						state.get_as_number(component, "topY").map(|n| n as f32),
						state.get_as_number(component, "rightX").map(|n| n as f32),
						state.get_as_number(component, "bottomY").map(|n| n as f32)
					),
				_ => fail!()
			}
		}
	}

	/// Returns the camera matrix of the scene.
	pub fn get_camera(state: &EntitiesState)
		-> Option<na::Mat4<f32>>
	{
		let cameraInfos = state
			.get_visible_native_components("camera").move_iter()
			.max_by(|c| match state.get(c, "priority") { Ok(&::entities::Number(ref n)) => (((*n) * 1000f64) as int), _ => 1000 })
			.and_then(|c| match state.get(&c, "matrix") { Ok(&::entities::List(ref data)) => Some((c, data)), _ => None })
			.map(|(c, data)| (c, data.iter().filter_map(|elem| match elem { &::entities::Number(ref n) => Some(n.clone() as f32), _ => None }).collect::<Vec<f32>>()) );

		if cameraInfos.is_none() {
			return None;
		}

		let (cameraComponent, matrixData) = cameraInfos.unwrap();
		let matrix = na::Mat4::new(*matrixData.get(0), *matrixData.get(1), *matrixData.get(2), *matrixData.get(3), *matrixData.get(4), *matrixData.get(5), *matrixData.get(6), *matrixData.get(7), *matrixData.get(8), *matrixData.get(9), *matrixData.get(10), *matrixData.get(11), *matrixData.get(12), *matrixData.get(13), *matrixData.get(14), *matrixData.get(15));

		let position = ::physics::PhysicsSystem::get_entity_position(state, &state.get_owner(&cameraComponent).unwrap());
		let positionMatrix = na::Mat4::new(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -position.x, -position.y, -position.z, 1.0);

		Some(positionMatrix * matrix)
	}
}
<commit_msg>Minor style change in display system<commit_after>use super::managed_display::ManagedDisplay;
use entities::{ EntitiesState, EntitiesHelper, EntityID, ComponentID, NativeComponentType };
use nalgebra::na;
use nalgebra::na::{ Vec3, Eye };
use std::collections::{ HashSet, HashMap };
use std::sync::Arc;
use super::sprite_displayer::SpriteDisplayer;
use super::Drawable;
use physics;

mod custom_display_system;

pub struct DisplaySystem {
    display: Arc<ManagedDisplay>,
    customDisplay: custom_display_system::CustomDisplaySystem,
    sprites: HashMap<ComponentID, (Option<SpriteDisplayer>, String)>,
    logger: Box<::log::Logger>
}

impl DisplaySystem {
    pub fn new<L: ::log::Logger + 'static>(display: Arc<ManagedDisplay>, state: &EntitiesState,
                                           mut logger: L)
        -> DisplaySystem
    {
        declmagic_info!(logger, "created display system");

        let customDisplaySystem =
            custom_display_system::CustomDisplaySystem::new(display.clone(), state, logger.clone());

        DisplaySystem {
            display: display.clone(),
            customDisplay: customDisplaySystem,
            sprites: HashMap::new(),
            logger: box logger
        }
    }

    pub fn draw(&mut self, state: &EntitiesState, _: &f64)
    {
        self.update_sprite_displayers(state);

        let camera = DisplaySystem::get_camera(state).unwrap_or_else(|| {
            declmagic_warn!(self.logger, "no active camera on the scene");
            Eye::new_identity(4)
        });

        for (cmp, &(ref sprite, _)) in self.sprites.iter() {
            let pos = physics::PhysicsSystem::get_entity_position(state,
                &state.get_owner(cmp).unwrap());
            let translationMatrix = na::Mat4::new(
                1.0, 0.0, 0.0, 0.0,
                0.0, 1.0, 0.0, 0.0,
                0.0, 0.0, 1.0, 0.0,
                pos.x, pos.y, pos.z, 1.0
            );
            sprite.as_ref().map(|e| e.draw(&(translationMatrix * camera)));
        }

        self.customDisplay.draw(state);
    }

    fn update_sprite_displayers(&mut self, state: &EntitiesState)
    {
        // getting the list of all sprite displayer components
        let listOfComponents = state
            .get_visible_native_components("spriteDisplay").move_iter()
            .collect::<HashSet<ComponentID>>();

        // removing from the list the elements that have disappeared
        {
            let toRemove = self.sprites.keys()
                .filter(|e| !listOfComponents.contains(e.clone()))
                .map(|e| e.clone())
                .collect::<Vec<ComponentID>>();

            for c in toRemove.move_iter() {
                self.sprites.remove(&c);
            }
        }

        // adding elements that are not yet created
        {
            let toCreate = listOfComponents.iter()
                .filter(|e| !self.sprites.contains_key(e.clone()))
                .map(|e| e.clone())
                .collect::<Vec<ComponentID>>();

            for spriteDisplayComponent in toCreate.move_iter() {
                // inserting in sprites list
                self.sprites.insert(spriteDisplayComponent.clone(), (None, format!("")));
            }
        }

        // updating everything
        for (component, &(ref mut sprite, ref mut currTexName)) in self.sprites.mut_iter() {
            // getting the name of the texture
            let textureName = match state.get_as_string(component, "texture") {
                Some(s) => s,
                _ => {
                    // TODO:
                    //declmagic_error!(self.logger,
                    //   "component {} has no valid \"texture\" element", component)
                    continue
                }
            };

            if sprite.is_none() || currTexName.as_slice() != textureName.as_slice() {
                (*sprite) = Some(
                    SpriteDisplayer::new(self.display.clone(), textureName.as_slice()).unwrap()
                );
                *currTexName = textureName;
            }

            // getting coordinates
            match sprite {
                &Some(ref mut s) =>
                    s.set_rectangle_coords(
                        state.get_as_number(component, "leftX").map(|n| n as f32),
                        state.get_as_number(component, "topY").map(|n| n as f32),
                        state.get_as_number(component, "rightX").map(|n| n as f32),
                        state.get_as_number(component, "bottomY").map(|n| n as f32)
                    ),
                _ => fail!()
            }
        }
    }

    /// Returns the camera matrix of the scene.
    pub fn get_camera(state: &EntitiesState)
        -> Option<na::Mat4<f32>>
    {
        let cameraInfos = state
            .get_visible_native_components("camera")
            .move_iter()
            .max_by(|c|
                match state.get_as_number(c, "priority") {
                    Some(n) => (n * 1000f64) as int,
                    _ => 1000
                })
            .and_then(|c|
                match state.get(&c, "matrix") {
                    Ok(&::entities::List(ref data)) => Some((c, data)),
                    _ => None
                })
            .map(|(c, data)| {
                (c, data.iter()
                    .filter_map(|elem|
                        match elem {
                            &::entities::Number(ref n) => Some(n.clone() as f32),
                            _ => None
                        })
                    .collect::<Vec<f32>>())
            });

        if cameraInfos.is_none() {
            return None;
        }

        let (cameraComponent, matrixData) = cameraInfos.unwrap();
        let matrix = na::Mat4::new(*matrixData.get(0), *matrixData.get(1), *matrixData.get(2),
            *matrixData.get(3), *matrixData.get(4), *matrixData.get(5), *matrixData.get(6),
            *matrixData.get(7), *matrixData.get(8), *matrixData.get(9), *matrixData.get(10),
            *matrixData.get(11), *matrixData.get(12), *matrixData.get(13), *matrixData.get(14),
            *matrixData.get(15));

        let position = physics::PhysicsSystem::get_entity_position(state,
            &state.get_owner(&cameraComponent).unwrap());

        let positionMatrix = na::Mat4::new(
            1.0, 0.0, 0.0, 0.0,
            0.0, 1.0, 0.0, 0.0,
            0.0, 0.0, 1.0, 0.0,
            -position.x, -position.y, -position.z, 1.0
        );

        Some(positionMatrix * matrix)
    }
}
<|endoftext|>


<commit_before>generate_error_imports!();

generate_error_types!(NoteError, NoteErrorKind,
    StoreWriteError       => "Error writing store",
    StoreReadError        => "Error reading store",
    HeaderTypeError       => "Header type error",
    NoteToEntryConversion => "Error converting Note instance to Entry instance"
);

<commit_msg>libimagnotes: use generate_error_module!() macro and reexport generated types<commit_after>generate_error_module!(
    generate_error_types!(NoteError, NoteErrorKind,
        StoreWriteError       => "Error writing store",
        StoreReadError        => "Error reading store",
        HeaderTypeError       => "Header type error",
        NoteToEntryConversion => "Error converting Note instance to Entry instance"
    );
);

pub use self::error::NoteError;
pub use self::error::NoteErrorKind;

<|endoftext|>