<commit_before>use crate::config::*;
use crate::errors::*;
use crate::process_handling::*;
use crate::report::report_coverage;
use crate::source_analysis::LineAnalysis;
use crate::statemachine::*;
use crate::test_loader::*;
use crate::traces::*;
use cargo::core::{compiler::{CompileMode, ProfileKind}, Package, Shell, Workspace};
use cargo::ops;
use cargo::ops::{
    clean, compile, CleanOptions, CompileFilter, CompileOptions, FilterRule, LibRule, Packages,
    TestOptions,
};
use cargo::util::{homedir, Config as CargoConfig};
use log::{debug, info, trace, warn};
use nix::unistd::*;
use std::collections::HashMap;
use std::env;
use std::ffi::CString;
use std::path::{Path, PathBuf};
use walkdir::WalkDir;

pub mod breakpoint;
pub mod config;
pub mod errors;
mod process_handling;
pub mod report;
mod source_analysis;
mod statemachine;
pub mod test_loader;
pub mod traces;

mod ptrace_control;

static DOCTEST_FOLDER: &str = "target/doctests";

pub fn run(config: &Config) -> Result<(), RunError> {
    let (tracemap, ret) = launch_tarpaulin(config)?;
    report_coverage(config, &tracemap)?;

    if ret == 0 {
        Ok(())
    } else {
        Err(RunError::TestFailed)
    }
}

/// Launches tarpaulin with the given configuration.
pub fn launch_tarpaulin(config: &Config) -> Result<(TraceMap, i32), RunError> {
    setup_environment(&config);
    cargo::core::enable_nightly_features();
    let cwd = match config.manifest.parent() {
        Some(p) => p.to_path_buf(),
        None => PathBuf::new(),
    };
    let home = match homedir(&cwd) {
        Some(h) => h,
        None => {
            warn!("Warning failed to find home directory.");
            PathBuf::new()
        }
    };
    let mut cargo_config = CargoConfig::new(Shell::new(), cwd, home);
    let flag_quiet = if config.verbose { None } else { Some(true) };

    // This shouldn't fail so no checking the error.
    let _ = cargo_config.configure(
        0u32,
        flag_quiet,
        &None,
        config.frozen,
        config.locked,
        config.offline,
        &config.target_dir,
        &config.unstable_features,
    );

    let workspace = Workspace::new(config.manifest.as_path(), &cargo_config)
        .map_err(|e| RunError::Manifest(e.to_string()))?;

    let mut compile_options = get_compile_options(&config, &cargo_config)?;

    info!("Running Tarpaulin");

    if config.force_clean {
        debug!("Cleaning project");
        // Clean isn't expected to fail and if it does it likely won't have an effect
        let clean_opt = CleanOptions {
            config: &cargo_config,
            spec: vec![],
            target: None,
            profile_specified: config.force_clean,
            profile_kind: ProfileKind::Dev,
            doc: false,
        };
        let _ = clean(&workspace, &clean_opt);
    }
    let mut result = TraceMap::new();
    let mut return_code = 0i32;
    let project_analysis = source_analysis::get_line_analysis(&workspace, config);
    info!("Building project");
    for copt in compile_options.drain(..) {
        let run_result = match copt.build_config.mode {
            CompileMode::Build | CompileMode::Test | CompileMode::Bench => {
                run_tests(&workspace, copt, &project_analysis, config)
            }
            CompileMode::Doctest => run_doctests(&workspace, copt, &project_analysis, config),
            e => {
                debug!("Internal tarpaulin error. Unsupported compile mode {:?}", e);
                Err(RunError::Internal)
            }
        }?;
        result.merge(&run_result.0);
        return_code |= run_result.1;
    }
    result.dedup();
    Ok((result, return_code))
}

fn run_tests(
    workspace: &Workspace,
    compile_options: CompileOptions,
    analysis: &HashMap<PathBuf, LineAnalysis>,
    config: &Config,
) -> Result<(TraceMap, i32), RunError> {
    let mut result = TraceMap::new();
    let mut return_code = 0i32;
    let compilation = compile(&workspace, &compile_options);
    match compilation {
        Ok(comp) => {
            if config.no_run {
                info!("Project compiled successfully");
                return Ok((result, return_code));
            }
            // Examples are always in the binaries list with tests!
            if config
                .run_types
                .iter()
                .any(|x| !(*x == RunType::Tests || *x == RunType::Doctests))
            {
                // If we have binaries we have other artefacts to run
                for binary in comp.binaries {
                    if let Some(res) = get_test_coverage(
                        &workspace,
                        None,
                        binary.as_path(),
                        analysis,
                        config,
                        false,
                        false,
                    )? {
                        result.merge(&res.0);
                        return_code |= res.1;
                    }
                }
            }
            for &(ref package, ref name, ref path) in &comp.tests {
                debug!("Processing {}", name);
                if let Some(res) = get_test_coverage(
                    &workspace,
                    Some(package),
                    path.as_path(),
                    analysis,
                    config,
                    true,
                    false,
                )? {
                    result.merge(&res.0);
                    return_code |= res.1;
                }
                if config.run_ignored {
                    if let Some(res) = get_test_coverage(
                        &workspace,
                        Some(package),
                        path.as_path(),
                        analysis,
                        config,
                        true,
                        true,
                    )? {
                        result.merge(&res.0);
                        return_code |= res.1;
                    }
                }
            }
            result.dedup();
            Ok((result, return_code))
        }
        Err(e) => return Err(RunError::TestCompile(e.to_string())),
    }
}

fn run_doctests(
    workspace: &Workspace,
    compile_options: CompileOptions,
    analysis: &HashMap<PathBuf, LineAnalysis>,
    config: &Config,
) -> Result<(TraceMap, i32), RunError> {
    info!("Running doctests");
    let mut result = TraceMap::new();
    let mut return_code = 0i32;

    let opts = TestOptions {
        no_run: false,
        no_fail_fast: false,
        compile_opts: compile_options,
    };
    let _ = ops::run_tests(workspace, &opts, &[]);

    let mut packages: Vec<PathBuf> = workspace
        .members()
        .filter_map(|p| p.manifest_path().parent())
        .map(|x| x.join(DOCTEST_FOLDER))
        .collect();

    if packages.is_empty() {
        let doctest_dir = match config.manifest.parent() {
            Some(p) => p.join(DOCTEST_FOLDER),
            None => PathBuf::from(DOCTEST_FOLDER),
        };
        packages.push(doctest_dir);
    }

    for dir in &packages {
        let walker = WalkDir::new(dir).into_iter();
        for dt in walker
            .filter_map(|e| e.ok())
            .filter(|e| match e.metadata() {
                Ok(ref m) if m.is_file() && m.len() != 0 => true,
                _ => false,
            })
        {
            if let Some(res) =
                get_test_coverage(&workspace, None, dt.path(), analysis, config, true, false)?
            {
                result.merge(&res.0);
                return_code |= res.1;
            }
        }
    }
    result.dedup();
    Ok((result, return_code))
}

fn get_compile_options<'a>(
    config: &Config,
    cargo_config: &'a CargoConfig,
) -> Result<Vec<CompileOptions<'a>>, RunError> {
    let mut result = Vec::new();
    for run_type in &config.run_types {
        let mut copt = CompileOptions::new(cargo_config, (*run_type).into())
            .map_err(|e| RunError::Cargo(e.to_string()))?;
        if run_type == &RunType::Tests {
            if let CompileFilter::Default {
                ref mut required_features_filterable,
            } = copt.filter
            {
                *required_features_filterable = true;
            }
        } else if run_type == &RunType::Doctests {
            copt.filter = CompileFilter::new(
                LibRule::True,
                FilterRule::Just(vec![]),
                FilterRule::Just(vec![]),
                FilterRule::Just(vec![]),
                FilterRule::Just(vec![]),
            );
        } else if run_type == &RunType::Examples {
            copt.filter = CompileFilter::new(
                LibRule::True,
                FilterRule::Just(vec![]),
                FilterRule::Just(vec![]),
                FilterRule::All,
                FilterRule::Just(vec![]),
            );
        }

        copt.features = config.features.clone();
        copt.all_features = config.all_features;
        copt.no_default_features = config.no_default_features;
        copt.build_config.profile_kind = match config.release {
            true => ProfileKind::Release,
            false => ProfileKind::Dev,
        };
        copt.spec =
            match Packages::from_flags(config.all, config.exclude.clone(), config.packages.clone())
            {
                Ok(spec) => spec,
                Err(e) => {
                    return Err(RunError::Packages(e.to_string()));
                }
            };
        result.push(copt);
    }
    Ok(result)
}

fn setup_environment(config: &Config) {
    env::set_var("TARPAULIN", "1");
    let common_opts =
        " -C relocation-model=dynamic-no-pic -C link-dead-code -C opt-level=0 -C debuginfo=2 ";
    let rustflags = "RUSTFLAGS";
    let mut value = common_opts.to_string();
    if config.release {
        value = format!("{}-C debug-assertions=off ", value);
    }
    if let Ok(vtemp) = env::var(rustflags) {
        value.push_str(vtemp.as_ref());
    }
    env::set_var(rustflags, value);
    // doesn't matter if we don't use it
    let rustdoc = "RUSTDOCFLAGS";
    let mut value = format!(
        "{} --persist-doctests {} -Z unstable-options ",
        common_opts, DOCTEST_FOLDER
    );
    if let Ok(vtemp) = env::var(rustdoc) {
        if !vtemp.contains("--persist-doctests") {
            value.push_str(vtemp.as_ref());
        }
    }
    env::set_var(rustdoc, value);
}

/// Returns the coverage statistics for a test executable in the given workspace
pub fn get_test_coverage(
    project: &Workspace,
    package: Option<&Package>,
    test: &Path,
    analysis: &HashMap<PathBuf, LineAnalysis>,
    config: &Config,
    can_quiet: bool,
    ignored: bool,
) -> Result<Option<(TraceMap, i32)>, RunError> {
    if !test.exists() {
        return Ok(None);
    }
    if let Err(e) = limit_affinity() {
        warn!("Failed to set processor affinity {}", e);
    }
    match fork() {
        Ok(ForkResult::Parent { child }) => {
            match collect_coverage(project, test, child, analysis, config) {
                Ok(t) => Ok(Some(t)),
                Err(e) => Err(RunError::TestCoverage(e.to_string())),
            }
        }
        Ok(ForkResult::Child) => {
            info!("Launching test");
            execute_test(test, package, ignored, can_quiet, config)?;
            Ok(None)
        }
        Err(err) => Err(RunError::TestCoverage(format!(
            "Failed to run test {}, Error: {}",
            test.display(),
            err.to_string()
        ))),
    }
}

/// Collects the coverage data from the launched test
fn collect_coverage(
    project: &Workspace,
    test_path: &Path,
    test: Pid,
    analysis: &HashMap<PathBuf, LineAnalysis>,
    config: &Config,
) -> Result<(TraceMap, i32), RunError> {
    let mut ret_code = 0;
    let mut traces = generate_tracemap(project, test_path, analysis, config)?;
    {
        trace!("Test PID is {}", test);
        let (mut state, mut data) = create_state_machine(test, &mut traces, config);
        loop {
            state = state.step(&mut data, config)?;
            if state.is_finished() {
                if let TestState::End(i) = state {
                    ret_code = i;
                }
                break;
            }
        }
    }
    Ok((traces, ret_code))
}

/// Launches the test executable
fn execute_test(
    test: &Path,
    package: Option<&Package>,
    ignored: bool,
    can_quiet: bool,
    config: &Config,
) -> Result<(), RunError> {
    let exec_path = CString::new(test.to_str().unwrap()).unwrap();
    info!("running {}", test.display());
    if let Some(pack) = package {
        if let Some(parent) = pack.manifest_path().parent() {
            let _ = env::set_current_dir(parent);
        }
    }

    let mut envars: Vec<CString> = Vec::new();

    for (key, value) in env::vars() {
        let mut temp = String::new();
        temp.push_str(key.as_str());
        temp.push('=');
        temp.push_str(value.as_str());
        envars.push(CString::new(temp).unwrap());
    }
    let mut argv = if ignored {
        vec![exec_path.clone(), CString::new("--ignored").unwrap()]
    } else {
        vec![exec_path.clone()]
    };
    if config.verbose {
        envars.push(CString::new("RUST_BACKTRACE=1").unwrap());
    } else if can_quiet {
        argv.push(CString::new("--quiet").unwrap());
    }
    for s in &config.varargs {
        argv.push(CString::new(s.as_bytes()).unwrap_or_default());
    }

    execute(exec_path, &argv, envars.as_slice())
}

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

    #[test]
    fn check_env() {
        let conf = Config::default();
        setup_environment(&conf);

        let tarp_var = env::var("TARPAULIN").unwrap();
        assert_eq!(tarp_var, "1");
    }
}
<commit_msg>Run cargo fmt<commit_after>use crate::config::*;
use crate::errors::*;
use crate::process_handling::*;
use crate::report::report_coverage;
use crate::source_analysis::LineAnalysis;
use crate::statemachine::*;
use crate::test_loader::*;
use crate::traces::*;
use cargo::core::{
    compiler::{CompileMode, ProfileKind},
    Package, Shell, Workspace,
};
use cargo::ops;
use cargo::ops::{
    clean, compile, CleanOptions, CompileFilter, CompileOptions, FilterRule, LibRule, Packages,
    TestOptions,
};
use cargo::util::{homedir, Config as CargoConfig};
use log::{debug, info, trace, warn};
use nix::unistd::*;
use std::collections::HashMap;
use std::env;
use std::ffi::CString;
use std::path::{Path, PathBuf};
use walkdir::WalkDir;

pub mod breakpoint;
pub mod config;
pub mod errors;
mod process_handling;
pub mod report;
mod source_analysis;
mod statemachine;
pub mod test_loader;
pub mod traces;

mod ptrace_control;

static DOCTEST_FOLDER: &str = "target/doctests";

pub fn run(config: &Config) -> Result<(), RunError> {
    let (tracemap, ret) = launch_tarpaulin(config)?;
    report_coverage(config, &tracemap)?;

    if ret == 0 {
        Ok(())
    } else {
        Err(RunError::TestFailed)
    }
}

/// Launches tarpaulin with the given configuration.
pub fn launch_tarpaulin(config: &Config) -> Result<(TraceMap, i32), RunError> {
    setup_environment(&config);
    cargo::core::enable_nightly_features();
    let cwd = match config.manifest.parent() {
        Some(p) => p.to_path_buf(),
        None => PathBuf::new(),
    };
    let home = match homedir(&cwd) {
        Some(h) => h,
        None => {
            warn!("Warning failed to find home directory.");
            PathBuf::new()
        }
    };
    let mut cargo_config = CargoConfig::new(Shell::new(), cwd, home);
    let flag_quiet = if config.verbose { None } else { Some(true) };

    // This shouldn't fail so no checking the error.
    let _ = cargo_config.configure(
        0u32,
        flag_quiet,
        &None,
        config.frozen,
        config.locked,
        config.offline,
        &config.target_dir,
        &config.unstable_features,
    );

    let workspace = Workspace::new(config.manifest.as_path(), &cargo_config)
        .map_err(|e| RunError::Manifest(e.to_string()))?;

    let mut compile_options = get_compile_options(&config, &cargo_config)?;

    info!("Running Tarpaulin");

    if config.force_clean {
        debug!("Cleaning project");
        // Clean isn't expected to fail and if it does it likely won't have an effect
        let clean_opt = CleanOptions {
            config: &cargo_config,
            spec: vec![],
            target: None,
            profile_specified: config.force_clean,
            profile_kind: ProfileKind::Dev,
            doc: false,
        };
        let _ = clean(&workspace, &clean_opt);
    }
    let mut result = TraceMap::new();
    let mut return_code = 0i32;
    let project_analysis = source_analysis::get_line_analysis(&workspace, config);
    info!("Building project");
    for copt in compile_options.drain(..) {
        let run_result = match copt.build_config.mode {
            CompileMode::Build | CompileMode::Test | CompileMode::Bench => {
                run_tests(&workspace, copt, &project_analysis, config)
            }
            CompileMode::Doctest => run_doctests(&workspace, copt, &project_analysis, config),
            e => {
                debug!("Internal tarpaulin error. Unsupported compile mode {:?}", e);
                Err(RunError::Internal)
            }
        }?;
        result.merge(&run_result.0);
        return_code |= run_result.1;
    }
    result.dedup();
    Ok((result, return_code))
}

fn run_tests(
    workspace: &Workspace,
    compile_options: CompileOptions,
    analysis: &HashMap<PathBuf, LineAnalysis>,
    config: &Config,
) -> Result<(TraceMap, i32), RunError> {
    let mut result = TraceMap::new();
    let mut return_code = 0i32;
    let compilation = compile(&workspace, &compile_options);
    match compilation {
        Ok(comp) => {
            if config.no_run {
                info!("Project compiled successfully");
                return Ok((result, return_code));
            }
            // Examples are always in the binaries list with tests!
            if config
                .run_types
                .iter()
                .any(|x| !(*x == RunType::Tests || *x == RunType::Doctests))
            {
                // If we have binaries we have other artefacts to run
                for binary in comp.binaries {
                    if let Some(res) = get_test_coverage(
                        &workspace,
                        None,
                        binary.as_path(),
                        analysis,
                        config,
                        false,
                        false,
                    )? {
                        result.merge(&res.0);
                        return_code |= res.1;
                    }
                }
            }
            for &(ref package, ref name, ref path) in &comp.tests {
                debug!("Processing {}", name);
                if let Some(res) = get_test_coverage(
                    &workspace,
                    Some(package),
                    path.as_path(),
                    analysis,
                    config,
                    true,
                    false,
                )? {
                    result.merge(&res.0);
                    return_code |= res.1;
                }
                if config.run_ignored {
                    if let Some(res) = get_test_coverage(
                        &workspace,
                        Some(package),
                        path.as_path(),
                        analysis,
                        config,
                        true,
                        true,
                    )? {
                        result.merge(&res.0);
                        return_code |= res.1;
                    }
                }
            }
            result.dedup();
            Ok((result, return_code))
        }
        Err(e) => return Err(RunError::TestCompile(e.to_string())),
    }
}

fn run_doctests(
    workspace: &Workspace,
    compile_options: CompileOptions,
    analysis: &HashMap<PathBuf, LineAnalysis>,
    config: &Config,
) -> Result<(TraceMap, i32), RunError> {
    info!("Running doctests");
    let mut result = TraceMap::new();
    let mut return_code = 0i32;

    let opts = TestOptions {
        no_run: false,
        no_fail_fast: false,
        compile_opts: compile_options,
    };
    let _ = ops::run_tests(workspace, &opts, &[]);

    let mut packages: Vec<PathBuf> = workspace
        .members()
        .filter_map(|p| p.manifest_path().parent())
        .map(|x| x.join(DOCTEST_FOLDER))
        .collect();

    if packages.is_empty() {
        let doctest_dir = match config.manifest.parent() {
            Some(p) => p.join(DOCTEST_FOLDER),
            None => PathBuf::from(DOCTEST_FOLDER),
        };
        packages.push(doctest_dir);
    }

    for dir in &packages {
        let walker = WalkDir::new(dir).into_iter();
        for dt in walker
            .filter_map(|e| e.ok())
            .filter(|e| match e.metadata() {
                Ok(ref m) if m.is_file() && m.len() != 0 => true,
                _ => false,
            })
        {
            if let Some(res) =
                get_test_coverage(&workspace, None, dt.path(), analysis, config, true, false)?
            {
                result.merge(&res.0);
                return_code |= res.1;
            }
        }
    }
    result.dedup();
    Ok((result, return_code))
}

fn get_compile_options<'a>(
    config: &Config,
    cargo_config: &'a CargoConfig,
) -> Result<Vec<CompileOptions<'a>>, RunError> {
    let mut result = Vec::new();
    for run_type in &config.run_types {
        let mut copt = CompileOptions::new(cargo_config, (*run_type).into())
            .map_err(|e| RunError::Cargo(e.to_string()))?;
        if run_type == &RunType::Tests {
            if let CompileFilter::Default {
                ref mut required_features_filterable,
            } = copt.filter
            {
                *required_features_filterable = true;
            }
        } else if run_type == &RunType::Doctests {
            copt.filter = CompileFilter::new(
                LibRule::True,
                FilterRule::Just(vec![]),
                FilterRule::Just(vec![]),
                FilterRule::Just(vec![]),
                FilterRule::Just(vec![]),
            );
        } else if run_type == &RunType::Examples {
            copt.filter = CompileFilter::new(
                LibRule::True,
                FilterRule::Just(vec![]),
                FilterRule::Just(vec![]),
                FilterRule::All,
                FilterRule::Just(vec![]),
            );
        }

        copt.features = config.features.clone();
        copt.all_features = config.all_features;
        copt.no_default_features = config.no_default_features;
        copt.build_config.profile_kind = match config.release {
            true => ProfileKind::Release,
            false => ProfileKind::Dev,
        };
        copt.spec =
            match Packages::from_flags(config.all, config.exclude.clone(), config.packages.clone())
            {
                Ok(spec) => spec,
                Err(e) => {
                    return Err(RunError::Packages(e.to_string()));
                }
            };
        result.push(copt);
    }
    Ok(result)
}

fn setup_environment(config: &Config) {
    env::set_var("TARPAULIN", "1");
    let common_opts =
        " -C relocation-model=dynamic-no-pic -C link-dead-code -C opt-level=0 -C debuginfo=2 ";
    let rustflags = "RUSTFLAGS";
    let mut value = common_opts.to_string();
    if config.release {
        value = format!("{}-C debug-assertions=off ", value);
    }
    if let Ok(vtemp) = env::var(rustflags) {
        value.push_str(vtemp.as_ref());
    }
    env::set_var(rustflags, value);
    // doesn't matter if we don't use it
    let rustdoc = "RUSTDOCFLAGS";
    let mut value = format!(
        "{} --persist-doctests {} -Z unstable-options ",
        common_opts, DOCTEST_FOLDER
    );
    if let Ok(vtemp) = env::var(rustdoc) {
        if !vtemp.contains("--persist-doctests") {
            value.push_str(vtemp.as_ref());
        }
    }
    env::set_var(rustdoc, value);
}

/// Returns the coverage statistics for a test executable in the given workspace
pub fn get_test_coverage(
    project: &Workspace,
    package: Option<&Package>,
    test: &Path,
    analysis: &HashMap<PathBuf, LineAnalysis>,
    config: &Config,
    can_quiet: bool,
    ignored: bool,
) -> Result<Option<(TraceMap, i32)>, RunError> {
    if !test.exists() {
        return Ok(None);
    }
    if let Err(e) = limit_affinity() {
        warn!("Failed to set processor affinity {}", e);
    }
    match fork() {
        Ok(ForkResult::Parent { child }) => {
            match collect_coverage(project, test, child, analysis, config) {
                Ok(t) => Ok(Some(t)),
                Err(e) => Err(RunError::TestCoverage(e.to_string())),
            }
        }
        Ok(ForkResult::Child) => {
            info!("Launching test");
            execute_test(test, package, ignored, can_quiet, config)?;
            Ok(None)
        }
        Err(err) => Err(RunError::TestCoverage(format!(
            "Failed to run test {}, Error: {}",
            test.display(),
            err.to_string()
        ))),
    }
}

/// Collects the coverage data from the launched test
fn collect_coverage(
    project: &Workspace,
    test_path: &Path,
    test: Pid,
    analysis: &HashMap<PathBuf, LineAnalysis>,
    config: &Config,
) -> Result<(TraceMap, i32), RunError> {
    let mut ret_code = 0;
    let mut traces = generate_tracemap(project, test_path, analysis, config)?;
    {
        trace!("Test PID is {}", test);
        let (mut state, mut data) = create_state_machine(test, &mut traces, config);
        loop {
            state = state.step(&mut data, config)?;
            if state.is_finished() {
                if let TestState::End(i) = state {
                    ret_code = i;
                }
                break;
            }
        }
    }
    Ok((traces, ret_code))
}

/// Launches the test executable
fn execute_test(
    test: &Path,
    package: Option<&Package>,
    ignored: bool,
    can_quiet: bool,
    config: &Config,
) -> Result<(), RunError> {
    let exec_path = CString::new(test.to_str().unwrap()).unwrap();
    info!("running {}", test.display());
    if let Some(pack) = package {
        if let Some(parent) = pack.manifest_path().parent() {
            let _ = env::set_current_dir(parent);
        }
    }

    let mut envars: Vec<CString> = Vec::new();

    for (key, value) in env::vars() {
        let mut temp = String::new();
        temp.push_str(key.as_str());
        temp.push('=');
        temp.push_str(value.as_str());
        envars.push(CString::new(temp).unwrap());
    }
    let mut argv = if ignored {
        vec![exec_path.clone(), CString::new("--ignored").unwrap()]
    } else {
        vec![exec_path.clone()]
    };
    if config.verbose {
        envars.push(CString::new("RUST_BACKTRACE=1").unwrap());
    } else if can_quiet {
        argv.push(CString::new("--quiet").unwrap());
    }
    for s in &config.varargs {
        argv.push(CString::new(s.as_bytes()).unwrap_or_default());
    }

    execute(exec_path, &argv, envars.as_slice())
}

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

    #[test]
    fn check_env() {
        let conf = Config::default();
        setup_environment(&conf);

        let tarp_var = env::var("TARPAULIN").unwrap();
        assert_eq!(tarp_var, "1");
    }
}
<|endoftext|>


<commit_before>//! A memory-safer wrapper around system dynamic library primitives.
//!
//! With this library you can load [dynamic libraries](struct.Library.html) and retrieve
//! [symbols](struct.Symbol.html) from the loaded libraries.
//!
//! Less safe platform specific bindings are available in the [`os::platform`](os/index.html)
//! modules.
use std::ffi::OsStr;
use std::fmt;
use std::marker;

#[cfg(unix)]
#[macro_use]
extern crate lazy_static;

#[cfg(unix)]
use self::os::unix as imp;
#[cfg(windows)]
use self::os::windows as imp;

pub mod os;
mod util;

pub type Result<T> = ::std::io::Result<T>;

/// A dynamically loaded library.
pub struct Library(imp::Library);

impl Library {
    /// Find and load a shared library (module).
    ///
    /// Locations where library is searched for is platform specific and can’t be adjusted
    /// portably.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// // on Unix
    /// let lib = Library::new("libm.so.6").unwrap();
    /// // on OS X
    /// let lib = Library::new("libm.dylib").unwrap();
    /// // on Windows
    /// let lib = Library::new("msvcrt.dll").unwrap();
    /// ```
    pub fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library> {
        imp::Library::new(filename).map(Library)
    }

    /// Get a symbol by name.
    ///
    /// Mangling or symbol rustification is not done: trying to `get` something like `x::y`
    /// will not work.
    ///
    /// You may append a null byte at the end of the byte string to avoid string allocation in some
    /// cases. E.g. for symbol `sin` you may write `b"sin\0"` instead of `b"sin"`.
    ///
    /// # Unsafety
    ///
    /// Symbol of arbitrary requested type is returned. Using a symbol with wrong type is not
    /// memory safe.
    ///
    /// # Examples
    ///
    /// Simple function:
    ///
    /// ```ignore
    /// let sin: Symbol<extern fn(f64) -> f64> = unsafe {
    ///     lib.get(b"sin\0").unwrap()
    /// };
    /// ```
    ///
    /// A static or TLS variable:
    ///
    /// ```ignore
    /// let errno: Symbol<*mut u32> = unsafe {
    ///     lib.get(b"errno\0").unwrap()
    /// };
    /// ```
    pub unsafe fn get<'lib, T>(&'lib self, symbol: &[u8]) -> Result<Symbol<'lib, T>> {
        self.0.get(symbol).map(|from| {
            Symbol {
                inner: from,
                pd: marker::PhantomData
            }
        })
    }
}

impl fmt::Debug for Library {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

/// Symbol from a library.
///
/// This type is a safeguard against using dynamically loaded symbols after a `Library` is
/// unloaded. Primary method to create an instance of a `Symbol` is via `Library::get`.
///
/// Due to implementation of the `Deref` trait, an instance of `Symbol` may be used as if it was a
/// function or variable directly, without taking care to “extract” function or variable manually
/// most of the time.
///
/// # Examples
///
/// ```ignore
/// let sin: Symbol<extern fn(f64) -> f64> = unsafe {
///     lib.get(b"sin\0").unwrap()
/// };
/// let sine0 = sin(0);
/// assert!(sine0 < 0.1E-10);
/// ```
pub struct Symbol<'lib, T: 'lib> {
    inner: imp::Symbol<T>,
    pd: marker::PhantomData<&'lib T>
}

impl<'lib, T> ::std::ops::Deref for Symbol<'lib, T> {
    type Target = T;
    fn deref(&self) -> &T {
        ::std::ops::Deref::deref(&self.inner)
    }
}

impl<'lib, T> fmt::Debug for Symbol<'lib, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.inner.fmt(f)
    }
}

#[cfg(all(unix, not(any(target_os="macos", target_os="ios", target_os="android"))))]
#[test]
fn libm() {
    let lib = Library::new("libm.so.6").unwrap();
    let sin: Symbol<extern fn(f64) -> f64> = unsafe {
        lib.get(b"sin").unwrap()
    };
    assert!(sin(::std::f64::INFINITY).is_nan());
    let errno: Symbol<*mut u32> = unsafe {
        lib.get(b"errno").unwrap()
    };
    assert!(unsafe { **errno } != 0);
    unsafe { **errno = 0; }
}
<commit_msg>Discourage users from exposing unsafe functions as safe and enable doc tests<commit_after>//! A memory-safer wrapper around system dynamic library primitives.
//!
//! With this library you can load [dynamic libraries](struct.Library.html) and retrieve
//! [symbols](struct.Symbol.html) from the loaded libraries.
//!
//! Less safe platform specific bindings are available in the [`os::platform`](os/index.html)
//! modules.
use std::ffi::OsStr;
use std::fmt;
use std::marker;

#[cfg(unix)]
#[macro_use]
extern crate lazy_static;

#[cfg(unix)]
use self::os::unix as imp;
#[cfg(windows)]
use self::os::windows as imp;

pub mod os;
mod util;

pub type Result<T> = ::std::io::Result<T>;

/// A dynamically loaded library.
pub struct Library(imp::Library);

impl Library {
    /// Find and load a shared library (module).
    ///
    /// Locations where library is searched for is platform specific and can’t be adjusted
    /// portably.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # use ::libloading::Library;
    /// // on Unix
    /// let lib = Library::new("libm.so.6").unwrap();
    /// // on OS X
    /// let lib = Library::new("libm.dylib").unwrap();
    /// // on Windows
    /// let lib = Library::new("msvcrt.dll").unwrap();
    /// ```
    pub fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library> {
        imp::Library::new(filename).map(Library)
    }

    /// Get a symbol by name.
    ///
    /// Mangling or symbol rustification is not done: trying to `get` something like `x::y`
    /// will not work.
    ///
    /// You may append a null byte at the end of the byte string to avoid string allocation in some
    /// cases. E.g. for symbol `sin` you may write `b"sin\0"` instead of `b"sin"`.
    ///
    /// # Unsafety
    ///
    /// Symbol of arbitrary requested type is returned. Using a symbol with wrong type is not
    /// memory safe.
    ///
    /// # Examples
    ///
    /// Simple function:
    ///
    /// ```no_run
    /// # use ::libloading::{ Library, Symbol };
    /// # let lib = Library::new("libm.so.6").unwrap();
    /// let sin: Symbol<unsafe extern fn(f64) -> f64> = unsafe {
    ///     lib.get(b"sin\0").unwrap()
    /// };
    /// ```
    ///
    /// A static or TLS variable:
    ///
    /// ```no_run
    /// # use ::libloading::{ Library, Symbol };
    /// # let lib = Library::new("libm.so.6").unwrap();
    /// let errno: Symbol<*mut u32> = unsafe {
    ///     lib.get(b"errno\0").unwrap()
    /// };
    /// ```
    pub unsafe fn get<'lib, T>(&'lib self, symbol: &[u8]) -> Result<Symbol<'lib, T>> {
        self.0.get(symbol).map(|from| {
            Symbol {
                inner: from,
                pd: marker::PhantomData
            }
        })
    }
}

impl fmt::Debug for Library {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

/// Symbol from a library.
///
/// This type is a safeguard against using dynamically loaded symbols after a `Library` is
/// unloaded. Primary method to create an instance of a `Symbol` is via `Library::get`.
///
/// Due to implementation of the `Deref` trait, an instance of `Symbol` may be used as if it was a
/// function or variable directly, without taking care to “extract” function or variable manually
/// most of the time.
///
/// # Examples
///
/// ```
/// # #[cfg(all(unix, not(any(target_os="macos", target_os="ios", target_os="android"))))]
/// # fn main() {
/// #     use ::libloading::{ Library, Symbol };
/// #     let lib = Library::new("libm.so.6").unwrap();
/// let sin: Symbol<unsafe extern fn(f64) -> f64> = unsafe {
///     lib.get(b"sin\0").unwrap()
/// };
///
/// let sine0 = unsafe { sin(0f64) };
/// assert!(sine0 < 0.1E-10);
/// # }
/// ```
pub struct Symbol<'lib, T: 'lib> {
    inner: imp::Symbol<T>,
    pd: marker::PhantomData<&'lib T>
}

impl<'lib, T> ::std::ops::Deref for Symbol<'lib, T> {
    type Target = T;
    fn deref(&self) -> &T {
        ::std::ops::Deref::deref(&self.inner)
    }
}

impl<'lib, T> fmt::Debug for Symbol<'lib, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.inner.fmt(f)
    }
}

#[cfg(all(unix, not(any(target_os="macos", target_os="ios", target_os="android"))))]
#[test]
fn libm() {
    let lib = Library::new("libm.so.6").unwrap();
    let sin: Symbol<unsafe extern fn(f64) -> f64> = unsafe {
        lib.get(b"sin").unwrap()
    };
    assert!(unsafe { sin(::std::f64::INFINITY) }.is_nan());
    let errno: Symbol<*mut u32> = unsafe {
        lib.get(b"errno").unwrap()
    };
    assert!(unsafe { **errno } != 0);
    unsafe { **errno = 0; }
}
<|endoftext|>


<commit_before>extern crate x11rb;

pub mod error;
mod run;

use std::thread;
use std::time::{ Duration, Instant };
use std::sync::{ Arc, RwLock };
use std::sync::mpsc::{ Sender, channel };
use std::collections::HashMap;
use x11rb::connection::{Connection, RequestConnection};
use x11rb::{COPY_DEPTH_FROM_PARENT, CURRENT_TIME};
use x11rb::errors::ConnectError;
use x11rb::protocol::{Event, xfixes};
use x11rb::protocol::xproto::{Atom, AtomEnum, ConnectionExt, CreateWindowAux, EventMask, Property, Window, WindowClass};
use x11rb::rust_connection::RustConnection;
use error::Error;

pub const INCR_CHUNK_SIZE: usize = 4000;
const POLL_DURATION: u64 = 50;
type SetMap = Arc<RwLock<HashMap<Atom, (Atom, Vec<u8>)>>>;

#[derive(Clone, Debug)]
pub struct Atoms {
    pub primary: Atom,
    pub clipboard: Atom,
    pub property: Atom,
    pub targets: Atom,
    pub string: Atom,
    pub utf8_string: Atom,
    pub incr: Atom,
}

impl Atoms {
    fn intern_all(conn: &RustConnection) -> Result<Atoms, Error> {
        let clipboard = conn.intern_atom(
            false,
            b"CLIPBOARD",
        )?;
        let property = conn.intern_atom(
            false,
            b"THIS_CLIPBOARD_OUT",
        )?;
        let targets = conn.intern_atom(
            false,
            b"TARGETS",
        )?;
        let utf8_string = conn.intern_atom(
            false,
            b"UTF8_STRING",
        )?;
        let incr = conn.intern_atom(
            false,
            b"INCR",
        )?;
        Ok(Atoms {
            primary: Atom::from(AtomEnum::PRIMARY),
            clipboard: clipboard.reply()?.atom,
            property: property.reply()?.atom,
            targets: targets.reply()?.atom,
            string: Atom::from(AtomEnum::STRING),
            utf8_string: utf8_string.reply()?.atom,
            incr: incr.reply()?.atom,
        })
    }
}

/// X11 Clipboard
pub struct Clipboard {
    pub getter: Context,
    pub setter: Arc<Context>,
    setmap: SetMap,
    send: Sender<Atom>
}

pub struct Context {
    pub connection: RustConnection,
    pub screen: usize,
    pub window: Window,
    pub atoms: Atoms
}

#[inline]
fn get_atom(connection: &RustConnection, name: &str) -> Result<Atom, Error> {
    let intern_atom = connection.intern_atom(
        false,
        name.as_bytes()
    )?;
    let reply = intern_atom.reply()
        .map_err(Error::XcbReply)?;
    Ok(reply.atom)
}

impl Context {
    pub fn new(displayname: Option<&str>) -> Result<Self, Error> {
        let (connection, screen) = RustConnection::connect(displayname)?;
        let window = connection.generate_id()?;

        {
            let screen = connection.setup().roots.get(screen)
                .ok_or(Error::XcbConnect(ConnectError::InvalidScreen))?;
            connection.create_window(
                COPY_DEPTH_FROM_PARENT,
                window,
                screen.root,
                0,
                0,
                1,
                1,
                0,
                WindowClass::INPUT_OUTPUT,
                screen.root_visual,
                &CreateWindowAux::new()
                    .event_mask(EventMask::STRUCTURE_NOTIFY | EventMask::PROPERTY_CHANGE)
            )?
                .check()?;
        }

        let atoms = Atoms::intern_all(&connection)?;

        Ok(Context { connection, screen, window, atoms })
    }

    pub fn get_atom(&self, name: &str) -> Result<Atom, Error> {
        get_atom(&self.connection, name)
    }
}

impl Clipboard {
    /// Create Clipboard.
    pub fn new() -> Result<Self, Error> {
        let getter = Context::new(None)?;
        let setter = Arc::new(Context::new(None)?);
        let setter2 = Arc::clone(&setter);
        let setmap = Arc::new(RwLock::new(HashMap::new()));
        let setmap2 = Arc::clone(&setmap);

        let (sender, receiver) = channel();
        let max_length = setter.connection.maximum_request_bytes();
        thread::spawn(move || run::run(&setter2, &setmap2, max_length, &receiver));

        Ok(Clipboard { getter, setter, setmap, send: sender })
    }

    fn process_event<T>(&self, buff: &mut Vec<u8>, selection: Atom, target: Atom, property: Atom, timeout: T, use_xfixes: bool)
        -> Result<(), Error>
        where T: Into<Option<Duration>>
    {
        let mut is_incr = false;
        let timeout = timeout.into();
        let start_time =
            if timeout.is_some() { Some(Instant::now()) }
            else { None };

        loop {
            if timeout.into_iter()
                .zip(start_time)
                .next()
                .map(|(timeout, time)| (Instant::now() - time) >= timeout)
                .unwrap_or(false)
            {
                return Err(Error::Timeout);
            }

            let event = match use_xfixes {
                true => self.getter.connection.wait_for_event()?,
                false => {
                    match self.getter.connection.poll_for_event()? {
                        Some(event) => event,
                        None => {
                            thread::park_timeout(Duration::from_millis(POLL_DURATION));
                            continue
                        }
                    }
                }
            };

            match event {
                Event::XfixesSelectionNotify(event) if use_xfixes => {
                    self.getter.connection.convert_selection(
                        self.getter.window,
                        selection,
                        target,
                        property,
                        event.timestamp,
                    )?.check()?;
                }
                Event::SelectionNotify(event) => {
                    if event.selection != selection { continue };

                    // Note that setting the property argument to None indicates that the
                    // conversion requested could not be made.
                    if event.property == Atom::from(AtomEnum::NONE) {
                        break;
                    }

                    let reply = self.getter.connection.get_property(
                        false,
                        self.getter.window,
                        event.property,
                        AtomEnum::NONE,
                        buff.len() as u32,
                        u32::MAX
                    )?.reply()?;

                    if reply.type_ == self.getter.atoms.incr {
                        if let Some(mut value) = reply.value32() {
                            if let Some(size) = value.next() {
                                buff.reserve(size as usize);
                            }
                        }
                        self.getter.connection.delete_property(
                            self.getter.window,
                            property
                        )?.check()?;
                        is_incr = true;
                        continue
                    } else if reply.type_ != target {
                        return Err(Error::UnexpectedType(reply.type_));
                    }

                    buff.extend_from_slice(&reply.value);
                    break
                }

                Event::PropertyNotify(event) if is_incr => {
                    if event.state != Property::NEW_VALUE { continue };

                    let cookie = self.getter.connection.get_property(
                        false,
                        self.getter.window,
                        property,
                        AtomEnum::NONE,
                        0,
                        0
                    )?;

                    let length = cookie.reply()?.bytes_after;

                    let cookie = self.getter.connection.get_property(
                        true,
                        self.getter.window,
                        property,
                        AtomEnum::NONE,
                        0, length
                    )?;
                    let reply = cookie.reply()?;
                    if reply.type_ != target { continue };

                    let value = reply.value;

                    if !value.is_empty() {
                        buff.extend_from_slice(&value);
                    } else {
                        break
                    }
                },
                _ => ()
            }
        }
        Ok(())
    }

    /// load value.
    pub fn load<T>(&self, selection: Atom, target: Atom, property: Atom, timeout: T)
        -> Result<Vec<u8>, Error>
        where T: Into<Option<Duration>>
    {
        let mut buff = Vec::new();
        let timeout = timeout.into();

        self.getter.connection.convert_selection(
            self.getter.window,
            selection,
            target,
            property,
            CURRENT_TIME,
            // FIXME ^
            // Clients should not use CurrentTime for the time argument of a ConvertSelection request.
            // Instead, they should use the timestamp of the event that caused the request to be made.
        )?.check()?;

        self.process_event(&mut buff, selection, target, property, timeout, false)?;

        self.getter.connection.delete_property(
            self.getter.window,
            property
        )?.check()?;

        Ok(buff)
    }

    /// wait for a new value and load it
    pub fn load_wait(&self, selection: Atom, target: Atom, property: Atom)
        -> Result<Vec<u8>, Error>
    {
        let mut buff = Vec::new();

        let screen = &self.getter.connection.setup().roots.get(self.getter.screen)
            .ok_or(Error::XcbConnect(ConnectError::InvalidScreen))?;

        xfixes::query_version(
            &self.getter.connection,
            5,
            0,
        )?;
        // Clear selection sources...
        xfixes::select_selection_input(
            &self.getter.connection,
            screen.root,
            self.getter.atoms.primary,
            xfixes::SelectionEventMask::default()
        )?;
        xfixes::select_selection_input(
            &self.getter.connection,
            screen.root,
            self.getter.atoms.clipboard,
            xfixes::SelectionEventMask::default()
        )?;
        // ...and set the one requested now
        xfixes::select_selection_input(
            &self.getter.connection,
            screen.root,
            selection,
            xfixes::SelectionEventMask::SET_SELECTION_OWNER |
                xfixes::SelectionEventMask::SELECTION_CLIENT_CLOSE |
                xfixes::SelectionEventMask::SELECTION_WINDOW_DESTROY
        )?.check()?;

        self.process_event(&mut buff, selection, target, property, None, true)?;

        self.getter.connection.delete_property(self.getter.window, property)?.check()?;

        Ok(buff)
    }

    /// store value.
    pub fn store<T: Into<Vec<u8>>>(&self, selection: Atom, target: Atom, value: T)
        -> Result<(), Error>
    {
        self.send.send(selection)?;
        self.setmap
            .write()
            .map_err(|_| Error::Lock)?
            .insert(selection, (target, value.into()));

        self.setter.connection.set_selection_owner(
            self.setter.window,
            selection,
            CURRENT_TIME
        )?.check()?;

        if self.setter.connection.get_selection_owner(
            selection
        )?.reply()
            .map(|reply| reply.owner == self.setter.window)
            .unwrap_or(false) {
            Ok(())
        } else {
            Err(Error::Owner)
        }
    }
}
<commit_msg>Re-export exposed structs<commit_after>extern crate x11rb;

pub mod error;
mod run;

pub use x11rb::protocol::xproto::{Atom, Window};
pub use x11rb::rust_connection::RustConnection;

use std::thread;
use std::time::{ Duration, Instant };
use std::sync::{ Arc, RwLock };
use std::sync::mpsc::{ Sender, channel };
use std::collections::HashMap;
use x11rb::connection::{Connection, RequestConnection};
use x11rb::{COPY_DEPTH_FROM_PARENT, CURRENT_TIME};
use x11rb::errors::ConnectError;
use x11rb::protocol::{Event, xfixes};
use x11rb::protocol::xproto::{AtomEnum, ConnectionExt, CreateWindowAux, EventMask, Property, WindowClass};
use error::Error;

pub const INCR_CHUNK_SIZE: usize = 4000;
const POLL_DURATION: u64 = 50;
type SetMap = Arc<RwLock<HashMap<Atom, (Atom, Vec<u8>)>>>;

#[derive(Clone, Debug)]
pub struct Atoms {
    pub primary: Atom,
    pub clipboard: Atom,
    pub property: Atom,
    pub targets: Atom,
    pub string: Atom,
    pub utf8_string: Atom,
    pub incr: Atom,
}

impl Atoms {
    fn intern_all(conn: &RustConnection) -> Result<Atoms, Error> {
        let clipboard = conn.intern_atom(
            false,
            b"CLIPBOARD",
        )?;
        let property = conn.intern_atom(
            false,
            b"THIS_CLIPBOARD_OUT",
        )?;
        let targets = conn.intern_atom(
            false,
            b"TARGETS",
        )?;
        let utf8_string = conn.intern_atom(
            false,
            b"UTF8_STRING",
        )?;
        let incr = conn.intern_atom(
            false,
            b"INCR",
        )?;
        Ok(Atoms {
            primary: Atom::from(AtomEnum::PRIMARY),
            clipboard: clipboard.reply()?.atom,
            property: property.reply()?.atom,
            targets: targets.reply()?.atom,
            string: Atom::from(AtomEnum::STRING),
            utf8_string: utf8_string.reply()?.atom,
            incr: incr.reply()?.atom,
        })
    }
}

/// X11 Clipboard
pub struct Clipboard {
    pub getter: Context,
    pub setter: Arc<Context>,
    setmap: SetMap,
    send: Sender<Atom>
}

pub struct Context {
    pub connection: RustConnection,
    pub screen: usize,
    pub window: Window,
    pub atoms: Atoms
}

#[inline]
fn get_atom(connection: &RustConnection, name: &str) -> Result<Atom, Error> {
    let intern_atom = connection.intern_atom(
        false,
        name.as_bytes()
    )?;
    let reply = intern_atom.reply()
        .map_err(Error::XcbReply)?;
    Ok(reply.atom)
}

impl Context {
    pub fn new(displayname: Option<&str>) -> Result<Self, Error> {
        let (connection, screen) = RustConnection::connect(displayname)?;
        let window = connection.generate_id()?;

        {
            let screen = connection.setup().roots.get(screen)
                .ok_or(Error::XcbConnect(ConnectError::InvalidScreen))?;
            connection.create_window(
                COPY_DEPTH_FROM_PARENT,
                window,
                screen.root,
                0,
                0,
                1,
                1,
                0,
                WindowClass::INPUT_OUTPUT,
                screen.root_visual,
                &CreateWindowAux::new()
                    .event_mask(EventMask::STRUCTURE_NOTIFY | EventMask::PROPERTY_CHANGE)
            )?
                .check()?;
        }

        let atoms = Atoms::intern_all(&connection)?;

        Ok(Context { connection, screen, window, atoms })
    }

    pub fn get_atom(&self, name: &str) -> Result<Atom, Error> {
        get_atom(&self.connection, name)
    }
}

impl Clipboard {
    /// Create Clipboard.
    pub fn new() -> Result<Self, Error> {
        let getter = Context::new(None)?;
        let setter = Arc::new(Context::new(None)?);
        let setter2 = Arc::clone(&setter);
        let setmap = Arc::new(RwLock::new(HashMap::new()));
        let setmap2 = Arc::clone(&setmap);

        let (sender, receiver) = channel();
        let max_length = setter.connection.maximum_request_bytes();
        thread::spawn(move || run::run(&setter2, &setmap2, max_length, &receiver));

        Ok(Clipboard { getter, setter, setmap, send: sender })
    }

    fn process_event<T>(&self, buff: &mut Vec<u8>, selection: Atom, target: Atom, property: Atom, timeout: T, use_xfixes: bool)
        -> Result<(), Error>
        where T: Into<Option<Duration>>
    {
        let mut is_incr = false;
        let timeout = timeout.into();
        let start_time =
            if timeout.is_some() { Some(Instant::now()) }
            else { None };

        loop {
            if timeout.into_iter()
                .zip(start_time)
                .next()
                .map(|(timeout, time)| (Instant::now() - time) >= timeout)
                .unwrap_or(false)
            {
                return Err(Error::Timeout);
            }

            let event = match use_xfixes {
                true => self.getter.connection.wait_for_event()?,
                false => {
                    match self.getter.connection.poll_for_event()? {
                        Some(event) => event,
                        None => {
                            thread::park_timeout(Duration::from_millis(POLL_DURATION));
                            continue
                        }
                    }
                }
            };

            match event {
                Event::XfixesSelectionNotify(event) if use_xfixes => {
                    self.getter.connection.convert_selection(
                        self.getter.window,
                        selection,
                        target,
                        property,
                        event.timestamp,
                    )?.check()?;
                }
                Event::SelectionNotify(event) => {
                    if event.selection != selection { continue };

                    // Note that setting the property argument to None indicates that the
                    // conversion requested could not be made.
                    if event.property == Atom::from(AtomEnum::NONE) {
                        break;
                    }

                    let reply = self.getter.connection.get_property(
                        false,
                        self.getter.window,
                        event.property,
                        AtomEnum::NONE,
                        buff.len() as u32,
                        u32::MAX
                    )?.reply()?;

                    if reply.type_ == self.getter.atoms.incr {
                        if let Some(mut value) = reply.value32() {
                            if let Some(size) = value.next() {
                                buff.reserve(size as usize);
                            }
                        }
                        self.getter.connection.delete_property(
                            self.getter.window,
                            property
                        )?.check()?;
                        is_incr = true;
                        continue
                    } else if reply.type_ != target {
                        return Err(Error::UnexpectedType(reply.type_));
                    }

                    buff.extend_from_slice(&reply.value);
                    break
                }

                Event::PropertyNotify(event) if is_incr => {
                    if event.state != Property::NEW_VALUE { continue };

                    let cookie = self.getter.connection.get_property(
                        false,
                        self.getter.window,
                        property,
                        AtomEnum::NONE,
                        0,
                        0
                    )?;

                    let length = cookie.reply()?.bytes_after;

                    let cookie = self.getter.connection.get_property(
                        true,
                        self.getter.window,
                        property,
                        AtomEnum::NONE,
                        0, length
                    )?;
                    let reply = cookie.reply()?;
                    if reply.type_ != target { continue };

                    let value = reply.value;

                    if !value.is_empty() {
                        buff.extend_from_slice(&value);
                    } else {
                        break
                    }
                },
                _ => ()
            }
        }
        Ok(())
    }

    /// load value.
    pub fn load<T>(&self, selection: Atom, target: Atom, property: Atom, timeout: T)
        -> Result<Vec<u8>, Error>
        where T: Into<Option<Duration>>
    {
        let mut buff = Vec::new();
        let timeout = timeout.into();

        self.getter.connection.convert_selection(
            self.getter.window,
            selection,
            target,
            property,
            CURRENT_TIME,
            // FIXME ^
            // Clients should not use CurrentTime for the time argument of a ConvertSelection request.
            // Instead, they should use the timestamp of the event that caused the request to be made.
        )?.check()?;

        self.process_event(&mut buff, selection, target, property, timeout, false)?;

        self.getter.connection.delete_property(
            self.getter.window,
            property
        )?.check()?;

        Ok(buff)
    }

    /// wait for a new value and load it
    pub fn load_wait(&self, selection: Atom, target: Atom, property: Atom)
        -> Result<Vec<u8>, Error>
    {
        let mut buff = Vec::new();

        let screen = &self.getter.connection.setup().roots.get(self.getter.screen)
            .ok_or(Error::XcbConnect(ConnectError::InvalidScreen))?;

        xfixes::query_version(
            &self.getter.connection,
            5,
            0,
        )?;
        // Clear selection sources...
        xfixes::select_selection_input(
            &self.getter.connection,
            screen.root,
            self.getter.atoms.primary,
            xfixes::SelectionEventMask::default()
        )?;
        xfixes::select_selection_input(
            &self.getter.connection,
            screen.root,
            self.getter.atoms.clipboard,
            xfixes::SelectionEventMask::default()
        )?;
        // ...and set the one requested now
        xfixes::select_selection_input(
            &self.getter.connection,
            screen.root,
            selection,
            xfixes::SelectionEventMask::SET_SELECTION_OWNER |
                xfixes::SelectionEventMask::SELECTION_CLIENT_CLOSE |
                xfixes::SelectionEventMask::SELECTION_WINDOW_DESTROY
        )?.check()?;

        self.process_event(&mut buff, selection, target, property, None, true)?;

        self.getter.connection.delete_property(self.getter.window, property)?.check()?;

        Ok(buff)
    }

    /// store value.
    pub fn store<T: Into<Vec<u8>>>(&self, selection: Atom, target: Atom, value: T)
        -> Result<(), Error>
    {
        self.send.send(selection)?;
        self.setmap
            .write()
            .map_err(|_| Error::Lock)?
            .insert(selection, (target, value.into()));

        self.setter.connection.set_selection_owner(
            self.setter.window,
            selection,
            CURRENT_TIME
        )?.check()?;

        if self.setter.connection.get_selection_owner(
            selection
        )?.reply()
            .map(|reply| reply.owner == self.setter.window)
            .unwrap_or(false) {
            Ok(())
        } else {
            Err(Error::Owner)
        }
    }
}
<|endoftext|>


<commit_before>//! Body Parser middleware for Iron
#![crate_id = "bodyparser"]
#![license = "MIT"]

extern crate iron;
extern crate serialize;

use iron::{Ingot, Alloy, Request, Response};
use iron::ingot::{Status, Continue};

use serialize::json;
use serialize::json::Json;

#[deriving(Clone)]
struct Parsed(Json);

#[deriving(Clone)]
pub struct BodyParser;

impl BodyParser {
    pub fn new() -> BodyParser {
        BodyParser
    }
}

impl<Rq: Request, Rs: Response> Ingot<Rq, Rs> for BodyParser {
    fn enter(&mut self, _rq: &mut Rq, _rs: &mut Rs, alloy: &mut Alloy) -> Status {
        if _rq.body().len() != 0 {
            println!("its not 0")
            alloy.insert::<Parsed>(Parsed(parse_body(_rq.body())));
        }
        Continue
    }
}

fn parse_body(x:&str) -> Json {
    let json_object = json::from_str(x.as_slice());
    let obj = json_object.clone().unwrap();
    obj
}<commit_msg>(feat) Adjusted for new Middleware process<commit_after>//! Body Parser middleware for Iron
#![crate_id = "bodyparser"]
#![license = "MIT"]

extern crate iron;
extern crate serialize;

use iron::{Request, Response, Middleware, Alloy};
use iron::middleware::{Status, Continue, Unwind};

use serialize::json;
use serialize::json::Json;

#[deriving(Clone)]
struct Parsed(Json);

#[deriving(Clone)]
pub struct BodyParser;

impl BodyParser {
    pub fn new() -> BodyParser {
        BodyParser
    }
}

impl Middleware for BodyParser {
    fn enter(&mut self, _req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        println!("Welcome to Body Parser")
        if _req.body.len() != 0 {
            println!("its not 0")
            alloy.insert::<Parsed>(Parsed(parse_body(_req.body.clone())));
        }
        Continue
    }
}

fn parse_body(x:String) -> Json {
    let json_object = json::from_str(x.clone().as_slice());
    let obj = json_object.clone().unwrap();
    obj
}<|endoftext|>


<commit_before>//! A macro to declare multiple mutable variables in one statement.
//!
//! `var! { ... }` is a generalised form of `let mut x = ...;`,
//! allowing for several mutable variables to be declared and
//! initialised at once, inspired by the keyword of the same name in
//! languages like Nim and C#.
//!
//! [Available on
//! crates.io](https://crates.io/crates/var). [Source](https://github.com/huonw/var).
//!
//! # Grammar
//!
//! ```not_rust
//! "var! {"
//!     (
//!         identifier (":" type)? "=" expression
//!     )*
//! "}"
//! ```
//!
//! where
//!
//! - `"..."` represents a literal `...`
//! - `(...)` is for grouping
//! - `*` is zero-or-more copies of the previous entity, *comma separated*, with
//!   optional trailing comma
//! - `?` is zero-or-one copies of the pervious entity (i.e. optional)
//!
//! Notably,
//!
//! - `var!` should always be invoked with `{}`s or else one will get
//!   compile errors (invoking a macro with `()` and `[]` mean the its internals
//!   are parsed as an expression, but declaring a variable with `let` is a
//!   statement),
//! - an initialising expression is required, unlike conventional `let`,
//! - pattern matching cannot be performed.
//!
//! # Examples
//!
//! ```rust
//! #[macro_use] extern crate var;
//!
//! fn fibonacci(n: u32) -> u64 {
//!     var! {
//!         a: u64 = 0,
//!         b = 1,
//!     }
//!     for _ in 0..n {
//!         let tmp = a + b;
//!         a = b;
//!         b = tmp;
//!     }
//!     return a
//! }
//!
//! fn main() {
//!     assert_eq!(fibonacci(10), 55);
//! }
//! ```

/// The main macro, see crate docs for details.
#[macro_export]
macro_rules! var {
    ($($vals: tt)*) => {
        __var_internals! {__make_things_work: () = (); $($vals)*,}
    };
}

/// Implementation details. **Do not use this directly.**
#[macro_export]
macro_rules! __var_internals {
    ($($name: ident : $t: ty = $init: expr),*; $(,)*) => {
        let ($(mut $name),* ,): ($($t),* ,) = ($($init),* ,);
    };
    ($($bname: ident : $bt: ty = $binit: expr),*; $name: ident = $init: expr, $($rest: tt)*) => {
        __var_internals!{$($bname: $bt = $binit,)* $name: _ = $init; $($rest)*}
    };
    ($($bname: ident : $bt: ty = $binit: expr),* ; $name: ident : $t: ty = $init: expr, $($rest: tt)*) => {
        __var_internals!{$($bname: $bt = $binit,)* $name: $t = $init; $($rest)*}
    };
}
<commit_msg>Add another doc example.<commit_after>//! A macro to declare multiple mutable variables in one statement.
//!
//! `var! { ... }` is a generalised form of `let mut x = ...;`,
//! allowing for several mutable variables to be declared and
//! initialised at once, inspired by the keyword of the same name in
//! languages like Nim and C#.
//!
//! [Available on
//! crates.io](https://crates.io/crates/var). [Source](https://github.com/huonw/var).
//!
//! # Grammar
//!
//! ```not_rust
//! "var! {"
//!     (
//!         identifier (":" type)? "=" expression
//!     )*
//! "}"
//! ```
//!
//! where
//!
//! - `"..."` represents a literal `...`
//! - `(...)` is for grouping
//! - `*` is zero-or-more copies of the previous entity, *comma separated*, with
//!   optional trailing comma
//! - `?` is zero-or-one copies of the pervious entity (i.e. optional)
//!
//! Notably,
//!
//! - `var!` should always be invoked with `{}`s or else one will get
//!   compile errors (invoking a macro with `()` and `[]` mean the its internals
//!   are parsed as an expression, but declaring a variable with `let` is a
//!   statement),
//! - an initialising expression is required, unlike conventional `let`,
//! - pattern matching cannot be performed.
//!
//! # Examples
//!
//! ```rust
//! #[macro_use] extern crate var;
//!
//! # fn main() {
//! var! {
//!     a = 1,
//!     b: &str = "foo",
//!     c = 3.0,
//! }
//!
//! a += 1;
//! b = "bar";
//! c *= 7.0;
//! # }
//! ```
//!
//! Generating Fibonacci numbers with a loop:
//!
//! ```rust
//! #[macro_use] extern crate var;
//!
//! fn fibonacci(n: u32) -> u64 {
//!     var! {
//!         a: u64 = 0,
//!         b = 1,
//!     }
//!     for _ in 0..n {
//!         let tmp = a + b;
//!         a = b;
//!         b = tmp;
//!     }
//!     return a
//! }
//!
//! fn main() {
//!     assert_eq!(fibonacci(10), 55);
//! }
//! ```

/// The main macro, see crate docs for details.
#[macro_export]
macro_rules! var {
    ($($vals: tt)*) => {
        __var_internals! {__make_things_work: () = (); $($vals)*,}
    };
}

/// Implementation details. **Do not use this directly.**
#[macro_export]
macro_rules! __var_internals {
    ($($name: ident : $t: ty = $init: expr),*; $(,)*) => {
        let ($(mut $name),* ,): ($($t),* ,) = ($($init),* ,);
    };
    ($($bname: ident : $bt: ty = $binit: expr),*; $name: ident = $init: expr, $($rest: tt)*) => {
        __var_internals!{$($bname: $bt = $binit,)* $name: _ = $init; $($rest)*}
    };
    ($($bname: ident : $bt: ty = $binit: expr),* ; $name: ident : $t: ty = $init: expr, $($rest: tt)*) => {
        __var_internals!{$($bname: $bt = $binit,)* $name: $t = $init; $($rest)*}
    };
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # libpnet
//!
//! `libpnet` provides a cross-platform API for low level networking using Rust.
//!
//! There are four key components:
//!
//!  * The `packet` module, allowing safe construction and manipulation of packets;
//!  * The `pnet_packet` crate, providing infrastructure for the packet module;
//!  * The `transport` module, which allows implementation of transport protocols;
//!  * The `datalink` module, which allows sending and receiving data link
//!    packets directly.
//!
//! ## Terminology
//!
//! The documentation uses the following terms interchangably:
//!
//!  * Layer 2, datalink layer;
//!  * Layer 3, network layer;
//!  * Layer 4, transport layer.
//!
//! Unless otherwise stated, all interactions with libpnet are in host-byte
//! order - any platform specific variations are handled internally.
//!
//! ## Examples
//!
//! More examples, including a packet logger, and a version of the echo server
//! written at the transport layer, can be found in the `examples/` directory.
//!
//! ### Ethernet echo server
//!
//! This (fairly useless) code implements an Ethernet echo server. Whenever a
//! packet is received on an interface, it echo's the packet back; reversing the
//! source and destination addresses.
//!
//! ```rust,no_run
//! extern crate pnet;
//!
//! use pnet::datalink::{self, NetworkInterface};
//! use pnet::datalink::Channel::Ethernet;
//! use pnet::packet::{Packet, MutablePacket};
//! use pnet::packet::ethernet::{EthernetPacket, MutableEthernetPacket};
//!
//! use std::env;
//!
//! // Invoke as echo <interface name>
//! fn main() {
//!     let interface_name = env::args().nth(1).unwrap();
//!     let interface_names_match =
//!         |iface: &NetworkInterface| iface.name == interface_name;
//!
//!     // Find the network interface with the provided name
//!     let interfaces = datalink::interfaces();
//!     let interface = interfaces.into_iter()
//!                               .filter(interface_names_match)
//!                               .next()
//!                               .unwrap();
//!
//!     // Create a new channel, dealing with layer 2 packets
//!     let (mut tx, mut rx) = match datalink::channel(&interface, Default::default()) {
//!         Ok(Ethernet(tx, rx)) => (tx, rx),
//!         Ok(_) => panic!("Unhandled channel type"),
//!         Err(e) => panic!("An error occurred when creating the datalink channel: {}", e)
//!     };
//!
//!     loop {
//!         match rx.next() {
//!             Ok(packet) => {
//!                 let packet = EthernetPacket::new(packet).unwrap();
//!
//!                 // Constructs a single packet, the same length as the the one received,
//!                 // using the provided closure. This allows the packet to be constructed
//!                 // directly in the write buffer, without copying. If copying is not a
//!                 // problem, you could also use send_to.
//!                 //
//!                 // The packet is sent once the closure has finished executing.
//!                 tx.build_and_send(1, packet.packet().len(),
//!                     &mut |mut new_packet| {
//!                         let mut new_packet = MutableEthernetPacket::new(new_packet).unwrap();
//!
//!                         // Create a clone of the original packet
//!                         new_packet.clone_from(&packet);
//!
//!                         // Switch the source and destination
//!                         new_packet.set_source(packet.get_destination());
//!                         new_packet.set_destination(packet.get_source());
//!                 });
//!             },
//!             Err(e) => {
//!                 // If an error occurs, we can handle it here
//!                 panic!("An error occurred while reading: {}", e);
//!             }
//!         }
//!     }
//! }
//! ```

#![deny(missing_docs)]
#![cfg_attr(feature = "nightly", feature(custom_attribute, plugin))]
#![cfg_attr(feature = "nightly", plugin(pnet_macros_plugin))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "benchmark", feature(test))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
// We can't implement Iterator since we use streaming iterators
#![cfg_attr(feature = "clippy", allow(should_implement_trait))]
#![cfg_attr(any(feature = "appveyor", feature = "travis"), deny(warnings))]

#[cfg(feature = "benchmark")]
extern crate test;

extern crate ipnetwork;

extern crate pnet_base;
extern crate pnet_datalink;
extern crate pnet_packet;
extern crate pnet_sys;
extern crate pnet_transport;

/// Support for sending and receiving data link layer packets.
pub mod datalink {
    pub use pnet_datalink::*;
}

/// Support for packet parsing and manipulation.
pub mod packet {
    pub use pnet_packet::*;
}

/// Support for sending and receiving transport layer packets.
pub mod transport {
    pub use pnet_transport::*;
}

pub mod util;

// NOTE should probably have a cfg(pnet_test_network) here, but cargo doesn't
//      allow custom --cfg flags
#[cfg(test)]
mod pnettest;
<commit_msg>reexport extern crate ipnetwork<commit_after>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # libpnet
//!
//! `libpnet` provides a cross-platform API for low level networking using Rust.
//!
//! There are four key components:
//!
//!  * The `packet` module, allowing safe construction and manipulation of packets;
//!  * The `pnet_packet` crate, providing infrastructure for the packet module;
//!  * The `transport` module, which allows implementation of transport protocols;
//!  * The `datalink` module, which allows sending and receiving data link
//!    packets directly.
//!
//! ## Terminology
//!
//! The documentation uses the following terms interchangably:
//!
//!  * Layer 2, datalink layer;
//!  * Layer 3, network layer;
//!  * Layer 4, transport layer.
//!
//! Unless otherwise stated, all interactions with libpnet are in host-byte
//! order - any platform specific variations are handled internally.
//!
//! ## Examples
//!
//! More examples, including a packet logger, and a version of the echo server
//! written at the transport layer, can be found in the `examples/` directory.
//!
//! ### Ethernet echo server
//!
//! This (fairly useless) code implements an Ethernet echo server. Whenever a
//! packet is received on an interface, it echo's the packet back; reversing the
//! source and destination addresses.
//!
//! ```rust,no_run
//! extern crate pnet;
//!
//! use pnet::datalink::{self, NetworkInterface};
//! use pnet::datalink::Channel::Ethernet;
//! use pnet::packet::{Packet, MutablePacket};
//! use pnet::packet::ethernet::{EthernetPacket, MutableEthernetPacket};
//!
//! use std::env;
//!
//! // Invoke as echo <interface name>
//! fn main() {
//!     let interface_name = env::args().nth(1).unwrap();
//!     let interface_names_match =
//!         |iface: &NetworkInterface| iface.name == interface_name;
//!
//!     // Find the network interface with the provided name
//!     let interfaces = datalink::interfaces();
//!     let interface = interfaces.into_iter()
//!                               .filter(interface_names_match)
//!                               .next()
//!                               .unwrap();
//!
//!     // Create a new channel, dealing with layer 2 packets
//!     let (mut tx, mut rx) = match datalink::channel(&interface, Default::default()) {
//!         Ok(Ethernet(tx, rx)) => (tx, rx),
//!         Ok(_) => panic!("Unhandled channel type"),
//!         Err(e) => panic!("An error occurred when creating the datalink channel: {}", e)
//!     };
//!
//!     loop {
//!         match rx.next() {
//!             Ok(packet) => {
//!                 let packet = EthernetPacket::new(packet).unwrap();
//!
//!                 // Constructs a single packet, the same length as the the one received,
//!                 // using the provided closure. This allows the packet to be constructed
//!                 // directly in the write buffer, without copying. If copying is not a
//!                 // problem, you could also use send_to.
//!                 //
//!                 // The packet is sent once the closure has finished executing.
//!                 tx.build_and_send(1, packet.packet().len(),
//!                     &mut |mut new_packet| {
//!                         let mut new_packet = MutableEthernetPacket::new(new_packet).unwrap();
//!
//!                         // Create a clone of the original packet
//!                         new_packet.clone_from(&packet);
//!
//!                         // Switch the source and destination
//!                         new_packet.set_source(packet.get_destination());
//!                         new_packet.set_destination(packet.get_source());
//!                 });
//!             },
//!             Err(e) => {
//!                 // If an error occurs, we can handle it here
//!                 panic!("An error occurred while reading: {}", e);
//!             }
//!         }
//!     }
//! }
//! ```

#![deny(missing_docs)]
#![cfg_attr(feature = "nightly", feature(custom_attribute, plugin))]
#![cfg_attr(feature = "nightly", plugin(pnet_macros_plugin))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "benchmark", feature(test))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
// We can't implement Iterator since we use streaming iterators
#![cfg_attr(feature = "clippy", allow(should_implement_trait))]
#![cfg_attr(any(feature = "appveyor", feature = "travis"), deny(warnings))]

#[cfg(feature = "benchmark")]
extern crate test;

pub extern crate ipnetwork;

extern crate pnet_base;
extern crate pnet_datalink;
extern crate pnet_packet;
extern crate pnet_sys;
extern crate pnet_transport;

/// Support for sending and receiving data link layer packets.
pub mod datalink {
    pub use pnet_datalink::*;
}

/// Support for packet parsing and manipulation.
pub mod packet {
    pub use pnet_packet::*;
}

/// Support for sending and receiving transport layer packets.
pub mod transport {
    pub use pnet_transport::*;
}

pub mod util;

// NOTE should probably have a cfg(pnet_test_network) here, but cargo doesn't
//      allow custom --cfg flags
#[cfg(test)]
mod pnettest;
<|endoftext|>


<commit_before>pub mod lc4 {

  // ConditionCode
  pub type CC = u8;

  pub const N : CC = 4;
  pub const Z : CC = 2;
  pub const P : CC = 1;

  pub type RName = u8;

  pub const R0 : RName = 0;
  pub const R1 : RName = 1;
  pub const R2 : RName = 2;
  pub const R3 : RName = 3;
  pub const R4 : RName = 4;
  pub const R5 : RName = 5;
  pub const R6 : RName = 6;
  pub const R7 : RName = 7;

  #[derive(PartialEq, Eq)]
  pub struct IMM11 { pub val : i16 }
  #[derive(PartialEq, Eq)]
  pub struct IMM9 { pub val : i16 }
  #[derive(PartialEq, Eq)]
  pub struct IMM7 { pub val : i8 }
  #[derive(PartialEq, Eq)]
  pub struct IMM6 { pub val : i8 }
  #[derive(PartialEq, Eq)]
  pub struct IMM5 { pub val : i8 }

  #[derive(PartialEq, Eq)]
  pub struct UIMM8 { pub val : u8 }
  #[derive(PartialEq, Eq)]
  pub struct UIMM7 { pub val : u8 }
  #[derive(PartialEq, Eq)]
  pub struct UIMM4 { pub val : u8 }

  // Instructions

  #[derive(PartialEq, Eq)]
  pub enum Inst {
    NOP,
    BR(CC,IMM9),
    ADD(RName, RName, RName),
    MUL(RName, RName, RName),
    SUB(RName, RName, RName),
    DIV(RName, RName, RName),
    ADDi(RName, RName, IMM5),
    CMP(RName, RName),
    CMPu(RName, RName),
    CMPi(RName, IMM7),
    CMPiu(RName, UIMM7),
    JSR(IMM11),
    JSRr(RName),
    AND(RName, RName, RName),
    NOT(RName, RName),
    OR(RName, RName, RName),
    XOR(RName, RName, RName),
    ANDi(RName, RName, IMM5),
    LDR(RName, RName, IMM6),
    STR(RName, RName, IMM6),
    RTI,
    CONST(RName, IMM9),
    SLL(RName, RName, UIMM4),
    SRA(RName, RName, UIMM4),
    SRL(RName, RName, UIMM4),
    MOD(RName, RName, RName),
    JMPr(RName),
    JMP(IMM11),
    HICONST(RName, UIMM8),
    TRAP(UIMM8)
  }

  // PSEUDO-instructions

  pub const RET : Inst = Inst::JMPr(R7);
  // LEA(RName, LABEL)
  // LC(RName, LABEL)

  // Assembly Directives
  /*
  .DATA
  .CODE
  .ADDR UIMM16
  .FALIGN
  .FILL IMM16
  .BLKW UIMM16
  .CONST IMM16
  .UCONST UIMM16
  */

}

pub mod controller {

  use lc4::*;

  #[derive(PartialEq, Eq)]
  enum DecodeError { BadOpcode }

  trait Controller {
    fn decode(&self) -> Result<Inst, DecodeError>;
  }

  macro_rules! opcode {
    ( $inst:expr ) => { ($inst & 0xF000 ) >> 12 };
  }

  macro_rules! br_opcode {
    ( $inst:expr ) => { ($inst & 0x0E00 ) >> 9 };
  }

  macro_rules! decode_imm9 {
    ( $inst:expr ) => { IMM9{val : if $inst & 0x0100 == 0 { $inst & 0x01FF } else { ($inst & 0x01FF) | 0xFE00  } as i16} };
  }

  impl Controller for u16 {
    fn decode(&self) -> Result<Inst, DecodeError> {
      match opcode!(self) {
        0b0000 =>
          match br_opcode!(self) {
            0b000 => Ok(Inst::NOP),
            a => Ok(Inst::BR(a as CC, decode_imm9!(self)))
          },
        _ => Err(DecodeError::BadOpcode)
      }
    }
  }

  #[test]
  fn decode_unit_tests () {
    assert!((0x0000 as u16).decode() == Ok(Inst::NOP));
  }
}

pub mod cpu {

  pub struct CPU {
    pub registers: [u16; 8],
    pub psr: u16,
    pub pc: u16,
    pub nzp: u8,
    pub memory: [u16; 2^16]
  }

}<commit_msg>cleanup<commit_after>pub mod lc4 {

  // ConditionCode
  pub type CC = u8;

  pub const N : CC = 4;
  pub const Z : CC = 2;
  pub const P : CC = 1;

  pub type RName = u8;

  pub const R0 : RName = 0;
  pub const R1 : RName = 1;
  pub const R2 : RName = 2;
  pub const R3 : RName = 3;
  pub const R4 : RName = 4;
  pub const R5 : RName = 5;
  pub const R6 : RName = 6;
  pub const R7 : RName = 7;

  #[derive(PartialEq, Eq)]
  pub struct IMM11 { pub value : i16 }
  #[derive(PartialEq, Eq)]
  pub struct IMM9 { pub value : i16 }
  #[derive(PartialEq, Eq)]
  pub struct IMM7 { pub value : i8 }
  #[derive(PartialEq, Eq)]
  pub struct IMM6 { pub value : i8 }
  #[derive(PartialEq, Eq)]
  pub struct IMM5 { pub value : i8 }

  #[derive(PartialEq, Eq)]
  pub struct UIMM8 { pub value : u8 }
  #[derive(PartialEq, Eq)]
  pub struct UIMM7 { pub value : u8 }
  #[derive(PartialEq, Eq)]
  pub struct UIMM4 { pub value : u8 }

  // Instructions

  #[derive(PartialEq, Eq)]
  pub enum Inst {
    NOP,
    BR(CC,IMM9),
    ADD(RName, RName, RName),
    MUL(RName, RName, RName),
    SUB(RName, RName, RName),
    DIV(RName, RName, RName),
    ADDi(RName, RName, IMM5),
    CMP(RName, RName),
    CMPu(RName, RName),
    CMPi(RName, IMM7),
    CMPiu(RName, UIMM7),
    JSR(IMM11),
    JSRr(RName),
    AND(RName, RName, RName),
    NOT(RName, RName),
    OR(RName, RName, RName),
    XOR(RName, RName, RName),
    ANDi(RName, RName, IMM5),
    LDR(RName, RName, IMM6),
    STR(RName, RName, IMM6),
    RTI,
    CONST(RName, IMM9),
    SLL(RName, RName, UIMM4),
    SRA(RName, RName, UIMM4),
    SRL(RName, RName, UIMM4),
    MOD(RName, RName, RName),
    JMPr(RName),
    JMP(IMM11),
    HICONST(RName, UIMM8),
    TRAP(UIMM8)
  }

  // PSEUDO-instructions

  pub const RET : Inst = Inst::JMPr(R7);
  // LEA(RName, LABEL)
  // LC(RName, LABEL)

  // Assembly Directives
  /*
  .DATA
  .CODE
  .ADDR UIMM16
  .FALIGN
  .FILL IMM16
  .BLKW UIMM16
  .CONST IMM16
  .UCONST UIMM16
  */

}

pub mod controller {

  use lc4::*;

  #[derive(PartialEq, Eq)]
  enum DecodeError { BadOpcode }

  trait Controller {
    fn decode(&self) -> Result<Inst, DecodeError>;
  }

  macro_rules! opcode {
    ( $inst:expr ) => { ($inst & 0xF000 ) >> 12 };
  }

  macro_rules! br_opcode {
    ( $inst:expr ) => { ($inst & 0x0E00 ) >> 9 };
  }

  macro_rules! decode_imm9 {
    ( $inst:expr ) => { IMM9{value : if $inst & 0x0100 == 0 { $inst & 0x01FF } else { ($inst & 0x01FF) | 0xFE00  } as i16} };
  }

  impl Controller for u16 {
    fn decode(&self) -> Result<Inst, DecodeError> {
      match opcode!(self) {
        0b0000 =>
          match br_opcode!(self) {
            0b000 => Ok(Inst::NOP),
            a => Ok(Inst::BR(a as CC, decode_imm9!(self)))
          },
        _ => Err(DecodeError::BadOpcode)
      }
    }
  }

  #[test]
  fn decode_unit_tests () {
    assert!(0.decode() == Ok(Inst::NOP));

    assert!(0b0000011000000110.decode() == Ok(Inst::BR(Z | P, IMM9{value:   6})));
    assert!(0b0000100000010110.decode() == Ok(Inst::BR(N    , IMM9{value:  22})));
    assert!(0b0000101111101110.decode() == Ok(Inst::BR(N | P, IMM9{value: -18})));

  }
}

pub mod cpu {

  pub struct CPU {
    pub registers: [u16; 8],
    pub psr: u16,
    pub pc: u16,
    pub nzp: u8,
    pub memory: [u16; 2^16]
  }

}<|endoftext|>


<commit_before>#![warn(missing_docs)]
//! Three.js inspired 3D engine in Rust.

#[macro_use]
extern crate bitflags;
extern crate cgmath;
extern crate froggy;
extern crate genmesh;
#[macro_use]
extern crate gfx;
extern crate image;
#[macro_use]
extern crate itertools;
#[macro_use]
extern crate log;
extern crate mint;
extern crate obj;
extern crate winit;
// OpenGL
#[cfg(feature = "opengl")]
extern crate gfx_device_gl;
#[cfg(feature = "opengl")]
extern crate gfx_window_glutin;
#[cfg(feature = "opengl")]
extern crate glutin;

#[macro_use]
mod macros;
mod camera;
mod factory;
mod input;
mod render;
mod scene;
#[cfg(feature = "opengl")]
mod window;

pub use camera::{OrbitControls, Orthographic, Perspective};
pub use factory::{Factory, FilterMethod, Geometry, GeometryShape, ShadowMap, Sampler, Texture, WrapMode};
pub use input::{Button, KeyAxis, Timer, Input,
                KEY_ESCAPE, KEY_SPACE, MOUSE_LEFT, MOUSE_RIGHT,
                AXIS_LEFT_RIGHT, AXIS_DOWN_UP};
pub use render::{ColorFormat, DepthFormat, Renderer, ShadowType, DebugQuadHandle};
pub use scene::{Color, Background, Material, NodeTransform, NodeInfo,
                Group, Sprite,
                AmbientLight, DirectionalLight, HemisphereLight, PointLight};
#[cfg(feature = "opengl")]
pub use window::Window;
#[cfg(feature = "opengl")]
pub use glutin::VirtualKeyCode as Key;

use std::sync::{mpsc, Arc, Mutex};

use cgmath::Transform as Transform_;
use factory::SceneId;
use render::{DynamicData, GpuData};

/// Pointer to a Node
pub type NodePointer = froggy::Pointer<Node>;
type Transform = cgmath::Decomposed<cgmath::Vector3<f32>, cgmath::Quaternion<f32>>;

#[derive(Clone, Debug)]
enum SubLight {
    Ambient,
    Directional,
    Hemisphere { ground: Color },
    Point,
}

#[derive(Clone, Debug)]
enum ShadowProjection {
    Ortho(Orthographic),
}

#[derive(Clone, Debug)]
struct LightData {
    color: Color,
    intensity: f32,
    sub_light: SubLight,
    shadow: Option<(ShadowMap, ShadowProjection)>,
}

#[derive(Debug)]
enum SubNode {
    Empty,
    Visual(Material, GpuData),
    Light(LightData),
}

/// Fat node of the scene graph.
///
/// `Node` is used by `three-rs` internally,
/// client code uses [`Object`](struct.Object.html) instead.
#[derive(Debug)]
pub struct Node {
    visible: bool,
    world_visible: bool,
    transform: Transform,
    world_transform: Transform,
    parent: Option<NodePointer>,
    scene_id: Option<SceneId>,
    sub_node: SubNode,
}

//Note: no local state should be here, only remote links
/// `Object` represents an entity that can be added to the scene.
///
/// There is no need to use `Object` directly, there are specific wrapper types
/// for each case (e.g. [`Camera`](struct.Camera.html),
/// [`AmbientLight`](struct.AmbientLight.html),
/// [`Mesh`](struct.Mesh.html), ...).
#[derive(Clone, Debug)]
pub struct Object {
    node: NodePointer,
    tx: mpsc::Sender<Message>,
}

/// Camera is used to render Scene with specific `Projection`.
pub struct Camera<P> {
    object: Object,
    /// Projection parameters of this camera.
    pub projection: P,
}

type Message = (froggy::WeakPointer<Node>, Operation);
enum Operation {
    SetParent(NodePointer),
    SetVisible(bool),
    SetTransform(Option<mint::Point3<f32>>, Option<mint::Quaternion<f32>>, Option<f32>),
    SetMaterial(Material),
    SetTexelRange(mint::Point2<i16>, mint::Vector2<u16>),
    SetShadow(ShadowMap, ShadowProjection),
}

type HubPtr = Arc<Mutex<Hub>>;
struct Hub {
    nodes: froggy::Storage<Node>,
    message_tx: mpsc::Sender<Message>,
    message_rx: mpsc::Receiver<Message>,
}

impl Hub {
    fn new() -> HubPtr {
        let (tx, rx) = mpsc::channel();
        let hub = Hub {
            nodes: froggy::Storage::new(),
            message_tx: tx,
            message_rx: rx,
        };
        Arc::new(Mutex::new(hub))
    }

    fn process_messages(&mut self) {
        while let Ok((pnode, operation)) = self.message_rx.try_recv() {
            let node = match pnode.upgrade() {
                Ok(ptr) => &mut self.nodes[&ptr],
                Err(_) => continue,
            };
            match operation {
                Operation::SetParent(parent) => {
                    node.parent = Some(parent);
                }
                Operation::SetVisible(visible) => {
                    node.visible = visible;
                }
                Operation::SetTransform(pos, rot, scale) => {
                    //TEMP! until mint integration is done in cgmath
                    if let Some(pos) = pos {
                        let p: [f32; 3] = pos.into();
                        node.transform.disp = p.into();
                    }
                    if let Some(rot) = rot {
                        let q: [f32; 3] = rot.v.into();
                        node.transform.rot = cgmath::Quaternion {
                            s: rot.s,
                            v: q.into(),
                        };
                    }
                    if let Some(scale) = scale {
                        node.transform.scale = scale;
                    }
                }
                Operation::SetMaterial(material) => {
                    if let SubNode::Visual(ref mut mat, _) = node.sub_node {
                        *mat = material;
                    }
                }
                Operation::SetTexelRange(base, size) => {
                    if let SubNode::Visual(ref mut material, _) = node.sub_node {
                        match *material {
                            Material::Sprite { ref mut map } => map.set_texel_range(base, size),
                            _ => panic!("Unsupported material for texel range request")
                        }
                    }
                }
                Operation::SetShadow(map, proj) => {
                    if let SubNode::Light(ref mut data) = node.sub_node {
                        data.shadow = Some((map, proj));
                    }
                }
            }
        }
        self.nodes.sync_pending();
    }

    fn update_graph(&mut self) {
        let mut cursor = self.nodes.cursor_alive();
        while let Some(mut item) = cursor.next() {
            if !item.visible {
                item.world_visible = false;
                continue
            }
            let (visibility, affilation, transform) = match item.parent {
                Some(ref parent_ptr) => {
                    let parent = item.look_back(parent_ptr).unwrap();
                    (parent.world_visible, parent.scene_id,
                     parent.world_transform.concat(&item.transform))
                },
                None => (true, item.scene_id, item.transform),
            };
            item.world_visible = visibility;
            item.scene_id = affilation;
            item.world_transform = transform;
        }
    }

    fn update_mesh(&mut self, mesh: &DynamicMesh) {
        match self.nodes[&mesh.node].sub_node {
            SubNode::Visual(_, ref mut gpu_data) =>
                gpu_data.pending = Some(mesh.dynamic.clone()),
            _ => unreachable!()
        }
    }
}

/// Game scene contains game objects and can be rendered by [`Camera`](struct.Camera.html).
pub struct Scene {
    unique_id: SceneId,
    node: NodePointer,
    tx: mpsc::Sender<Message>,
    hub: HubPtr,
    /// See [`Background`](struct.Background.html).
    pub background: scene::Background,
}

/// [`Geometry`](struct.Geometry.html) with some [`Material`](struct.Material.html).
pub struct Mesh {
    object: Object,
}

/// A dynamic version of a mesh allows changing the geometry on CPU side
/// in order to animate the mesh.
pub struct DynamicMesh {
    object: Object,
    geometry: Geometry,
    dynamic: DynamicData,
}
<commit_msg>Erroring on invalid look back<commit_after>#![warn(missing_docs)]
//! Three.js inspired 3D engine in Rust.

#[macro_use]
extern crate bitflags;
extern crate cgmath;
extern crate froggy;
extern crate genmesh;
#[macro_use]
extern crate gfx;
extern crate image;
#[macro_use]
extern crate itertools;
#[macro_use]
extern crate log;
extern crate mint;
extern crate obj;
extern crate winit;
// OpenGL
#[cfg(feature = "opengl")]
extern crate gfx_device_gl;
#[cfg(feature = "opengl")]
extern crate gfx_window_glutin;
#[cfg(feature = "opengl")]
extern crate glutin;

#[macro_use]
mod macros;
mod camera;
mod factory;
mod input;
mod render;
mod scene;
#[cfg(feature = "opengl")]
mod window;

pub use camera::{OrbitControls, Orthographic, Perspective};
pub use factory::{Factory, FilterMethod, Geometry, GeometryShape, ShadowMap, Sampler, Texture, WrapMode};
pub use input::{Button, KeyAxis, Timer, Input,
                KEY_ESCAPE, KEY_SPACE, MOUSE_LEFT, MOUSE_RIGHT,
                AXIS_LEFT_RIGHT, AXIS_DOWN_UP};
pub use render::{ColorFormat, DepthFormat, Renderer, ShadowType, DebugQuadHandle};
pub use scene::{Color, Background, Material, NodeTransform, NodeInfo,
                Group, Sprite,
                AmbientLight, DirectionalLight, HemisphereLight, PointLight};
#[cfg(feature = "opengl")]
pub use window::Window;
#[cfg(feature = "opengl")]
pub use glutin::VirtualKeyCode as Key;

use std::sync::{mpsc, Arc, Mutex};

use cgmath::Transform as Transform_;
use factory::SceneId;
use render::{DynamicData, GpuData};

/// Pointer to a Node
pub type NodePointer = froggy::Pointer<Node>;
type Transform = cgmath::Decomposed<cgmath::Vector3<f32>, cgmath::Quaternion<f32>>;

#[derive(Clone, Debug)]
enum SubLight {
    Ambient,
    Directional,
    Hemisphere { ground: Color },
    Point,
}

#[derive(Clone, Debug)]
enum ShadowProjection {
    Ortho(Orthographic),
}

#[derive(Clone, Debug)]
struct LightData {
    color: Color,
    intensity: f32,
    sub_light: SubLight,
    shadow: Option<(ShadowMap, ShadowProjection)>,
}

#[derive(Debug)]
enum SubNode {
    Empty,
    Visual(Material, GpuData),
    Light(LightData),
}

/// Fat node of the scene graph.
///
/// `Node` is used by `three-rs` internally,
/// client code uses [`Object`](struct.Object.html) instead.
#[derive(Debug)]
pub struct Node {
    visible: bool,
    world_visible: bool,
    transform: Transform,
    world_transform: Transform,
    parent: Option<NodePointer>,
    scene_id: Option<SceneId>,
    sub_node: SubNode,
}

//Note: no local state should be here, only remote links
/// `Object` represents an entity that can be added to the scene.
///
/// There is no need to use `Object` directly, there are specific wrapper types
/// for each case (e.g. [`Camera`](struct.Camera.html),
/// [`AmbientLight`](struct.AmbientLight.html),
/// [`Mesh`](struct.Mesh.html), ...).
#[derive(Clone, Debug)]
pub struct Object {
    node: NodePointer,
    tx: mpsc::Sender<Message>,
}

/// Camera is used to render Scene with specific `Projection`.
pub struct Camera<P> {
    object: Object,
    /// Projection parameters of this camera.
    pub projection: P,
}

type Message = (froggy::WeakPointer<Node>, Operation);
enum Operation {
    SetParent(NodePointer),
    SetVisible(bool),
    SetTransform(Option<mint::Point3<f32>>, Option<mint::Quaternion<f32>>, Option<f32>),
    SetMaterial(Material),
    SetTexelRange(mint::Point2<i16>, mint::Vector2<u16>),
    SetShadow(ShadowMap, ShadowProjection),
}

type HubPtr = Arc<Mutex<Hub>>;
struct Hub {
    nodes: froggy::Storage<Node>,
    message_tx: mpsc::Sender<Message>,
    message_rx: mpsc::Receiver<Message>,
}

impl Hub {
    fn new() -> HubPtr {
        let (tx, rx) = mpsc::channel();
        let hub = Hub {
            nodes: froggy::Storage::new(),
            message_tx: tx,
            message_rx: rx,
        };
        Arc::new(Mutex::new(hub))
    }

    fn process_messages(&mut self) {
        while let Ok((pnode, operation)) = self.message_rx.try_recv() {
            let node = match pnode.upgrade() {
                Ok(ptr) => &mut self.nodes[&ptr],
                Err(_) => continue,
            };
            match operation {
                Operation::SetParent(parent) => {
                    node.parent = Some(parent);
                }
                Operation::SetVisible(visible) => {
                    node.visible = visible;
                }
                Operation::SetTransform(pos, rot, scale) => {
                    //TEMP! until mint integration is done in cgmath
                    if let Some(pos) = pos {
                        let p: [f32; 3] = pos.into();
                        node.transform.disp = p.into();
                    }
                    if let Some(rot) = rot {
                        let q: [f32; 3] = rot.v.into();
                        node.transform.rot = cgmath::Quaternion {
                            s: rot.s,
                            v: q.into(),
                        };
                    }
                    if let Some(scale) = scale {
                        node.transform.scale = scale;
                    }
                }
                Operation::SetMaterial(material) => {
                    if let SubNode::Visual(ref mut mat, _) = node.sub_node {
                        *mat = material;
                    }
                }
                Operation::SetTexelRange(base, size) => {
                    if let SubNode::Visual(ref mut material, _) = node.sub_node {
                        match *material {
                            Material::Sprite { ref mut map } => map.set_texel_range(base, size),
                            _ => panic!("Unsupported material for texel range request")
                        }
                    }
                }
                Operation::SetShadow(map, proj) => {
                    if let SubNode::Light(ref mut data) = node.sub_node {
                        data.shadow = Some((map, proj));
                    }
                }
            }
        }
        self.nodes.sync_pending();
    }

    fn update_graph(&mut self) {
        let mut cursor = self.nodes.cursor_alive();
        while let Some(mut item) = cursor.next() {
            if !item.visible {
                item.world_visible = false;
                continue
            }
            let (visibility, affilation, transform) = match item.parent {
                Some(ref parent_ptr) => {
                    match item.look_back(parent_ptr) {
                        Some(parent) => {
                            (parent.world_visible,
                             parent.scene_id,
                             parent.world_transform.concat(&item.transform))
                        }
                        None => {
                            error!("Parent node was created after the child, ignoring");
                            (false, item.scene_id, item.transform)
                        }
                    }
                },
                None => (true, item.scene_id, item.transform),
            };
            item.world_visible = visibility;
            item.scene_id = affilation;
            item.world_transform = transform;
        }
    }

    fn update_mesh(&mut self, mesh: &DynamicMesh) {
        match self.nodes[&mesh.node].sub_node {
            SubNode::Visual(_, ref mut gpu_data) =>
                gpu_data.pending = Some(mesh.dynamic.clone()),
            _ => unreachable!()
        }
    }
}

/// Game scene contains game objects and can be rendered by [`Camera`](struct.Camera.html).
pub struct Scene {
    unique_id: SceneId,
    node: NodePointer,
    tx: mpsc::Sender<Message>,
    hub: HubPtr,
    /// See [`Background`](struct.Background.html).
    pub background: scene::Background,
}

/// [`Geometry`](struct.Geometry.html) with some [`Material`](struct.Material.html).
pub struct Mesh {
    object: Object,
}

/// A dynamic version of a mesh allows changing the geometry on CPU side
/// in order to animate the mesh.
pub struct DynamicMesh {
    object: Object,
    geometry: Geometry,
    dynamic: DynamicData,
}
<|endoftext|>