<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use std::path::{Path, PathBuf};

use codespan_reporting::term::termcolor::Buffer;

use anyhow::anyhow;
use itertools::Itertools;
use move_prover::{cli::Options, run_move_prover};
use move_prover_test_utils::{
    baseline_test::verify_or_update_baseline, extract_test_directives, read_env_var,
};
use tempfile::TempDir;

use datatest_stable::Requirements;
#[allow(unused_imports)]
use log::{debug, info, warn};
use std::sync::atomic::{AtomicBool, Ordering};
use walkdir::WalkDir;

const ENV_FLAGS: &str = "MVP_TEST_FLAGS";
const ENV_TEST_EXTENDED: &str = "MVP_TEST_X";
const ENV_TEST_INCONSISTENCY: &str = "MVP_TEST_INCONSISTENCY";
const ENV_TEST_FEATURE: &str = "MVP_TEST_FEATURE";
const ENV_TEST_ON_CI: &str = "MVP_TEST_ON_CI";
const INCONSISTENCY_TEST_FLAGS: &[&str] = &[
    "--dependency=../move-stdlib/modules",
    "--dependency=../diem-framework/modules",
    "--check-inconsistency",
];
const REGULAR_TEST_FLAGS: &[&str] = &[
    "--dependency=../move-stdlib/modules",
    "--dependency=../diem-framework/modules",
];

static NOT_CONFIGURED_WARNED: AtomicBool = AtomicBool::new(false);

/// A struct to describe a feature to test.
struct Feature {
    /// Name of this feature.
    name: &'static str,
    /// Flags specific to this feature.
    flags: &'static [&'static str],
    /// Inclusion mode.
    inclusion_mode: InclusionMode,
    /// Whether this feature will be tested in CI.
    enable_in_ci: bool,
    /// Whether this feature has as a separate baseline file.
    separate_baseline: bool,
    /// A static function pointer to the runner to be used for datatest. Since datatest
    /// does not support function values and closures, we need to have a different runner for
    /// each feature
    runner: fn(&Path) -> datatest_stable::Result<()>,
}

/// An inclusion mode. A feature may be run in one of these modes.
#[derive(Clone, Copy)]
enum InclusionMode {
    /// Only a test which has the comment `// also_include_for: <feature>` will be included.
    Explicit,
    /// Every test will be included unless it has the comment `// exclude_for: <feature>`.
    Implicit,
}

const TESTED_FEATURES: &[Feature] = &[
    Feature {
        name: "default",
        flags: &[],
        inclusion_mode: InclusionMode::Implicit,
        enable_in_ci: true,
        separate_baseline: false,
        runner: runner_default,
    },
    Feature {
        name: "cvc4",
        flags: &["--use-cvc4"],
        inclusion_mode: InclusionMode::Explicit,
        enable_in_ci: false, // Do not enable in CI until boogie <-> cvc4 issues are fixed
        separate_baseline: true,
        runner: runner_cvc4,
    },
];

fn get_feature_by_name(name: &str) -> &'static Feature {
    for feature in TESTED_FEATURES {
        if feature.name == name {
            return feature;
        }
    }
    panic!("feature not found")
}

fn runner_default(p: &Path) -> datatest_stable::Result<()> {
    test_runner_for_feature(p, get_feature_by_name("default"))
}
fn runner_cvc4(p: &Path) -> datatest_stable::Result<()> {
    test_runner_for_feature(p, get_feature_by_name("cvc4"))
}

/// Test runner for a given feature.
fn test_runner_for_feature(path: &Path, feature: &Feature) -> datatest_stable::Result<()> {
    // Use the below + `cargo test -- --test-threads=1` to identify a long running test
    //println!(">>> testing {}", path.to_string_lossy().to_string());

    info!(
        "testing {} with feature `{}` (flags = `{}`)",
        path.display(),
        feature.name,
        feature.flags.iter().map(|s| s.to_string()).join(" ")
    );

    let temp_dir = TempDir::new()?;
    std::fs::create_dir_all(temp_dir.path())?;
    let (mut args, baseline_path) = get_flags_and_baseline(temp_dir.path(), path, feature)?;

    args.insert(0, "mvp_test".to_owned());
    args.push("--verbose=warn".to_owned());
    // TODO: timeouts aren't handled correctly by the boogie wrapper but lead to hang. Determine
    //   reasons and reactivate.
    // args.push("--num-instances=2".to_owned()); // run two Boogie instances with different seeds
    // args.push("--sequential".to_owned());

    // Move source.
    args.push(path.to_string_lossy().to_string());

    let mut options = Options::create_from_args(&args)?;
    options.setup_logging_for_test();
    let no_tools = read_env_var("BOOGIE_EXE").is_empty()
        || !options.backend.use_cvc4 && read_env_var("Z3_EXE").is_empty()
        || options.backend.use_cvc4 && read_env_var("CVC4_EXE").is_empty();
    let baseline_valid =
        !no_tools || !extract_test_directives(path, "// no-boogie-test")?.is_empty();

    if no_tools {
        options.prover.generate_only = true;
        if NOT_CONFIGURED_WARNED
            .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
            .is_ok()
        {
            warn!(
                "Prover tools are not configured, verification tests will be skipped. \
        See https://github.com/diem/diem/tree/main/language/move-prover/doc/user/install.md \
        for instructions."
            );
        }
    }
    options.backend.check_tool_versions()?;
    options.prover.stable_test_output = true;
    options.backend.stable_test_output = true;

    let mut error_writer = Buffer::no_color();
    let mut diags = match run_move_prover(&mut error_writer, options) {
        Ok(()) => "".to_string(),
        Err(err) => format!("Move prover returns: {}\n", err),
    };
    if baseline_valid {
        if let Some(ref path) = baseline_path {
            diags += &String::from_utf8_lossy(&error_writer.into_inner()).to_string();
            verify_or_update_baseline(path.as_path(), &diags)?
        } else if !diags.is_empty() {
            return Err(anyhow!(
                "Unexpected prover output (expected none): {}{}",
                diags,
                String::from_utf8_lossy(&error_writer.into_inner())
            )
            .into());
        }
    }

    Ok(())
}

/// Returns flags and baseline file for this test run
fn get_flags_and_baseline(
    temp_dir: &Path,
    path: &Path,
    feature: &Feature,
) -> anyhow::Result<(Vec<String>, Option<PathBuf>)> {
    // Determine the way how to configure tests based on directory of the path.
    let path_str = path.to_string_lossy();

    let stdlib_test_flags = if read_env_var(ENV_TEST_INCONSISTENCY).is_empty() {
        REGULAR_TEST_FLAGS
    } else {
        INCONSISTENCY_TEST_FLAGS
    };

    let (base_flags, baseline_path) =
        if path_str.contains("diem-framework/") || path_str.contains("move-stdlib/") {
            (stdlib_test_flags, None)
        } else {
            (
                REGULAR_TEST_FLAGS,
                Some(path.with_extension(if feature.separate_baseline {
                    format!("{}_exp", feature.name)
                } else {
                    "exp".to_string()
                })),
            )
        };
    let mut flags = base_flags.iter().map(|s| (*s).to_string()).collect_vec();

    // Add flags specific to the feature.
    flags.extend(feature.flags.iter().map(|f| f.to_string()));

    // Add flags specified in the source.
    flags.extend(extract_test_directives(path, "// flag:")?);

    // Add flags specified via environment variable.
    flags.extend(shell_words::split(&read_env_var(ENV_FLAGS))?);

    // Create a temporary file for output. We inject the modifier to potentially prevent
    // any races between similar named files in different directories, as it appears TempPath
    // isn't working always.
    let base_name = format!("{}.bpl", path.file_stem().unwrap().to_str().unwrap());
    let output = temp_dir.join(base_name).to_str().unwrap().to_string();
    flags.push(format!("--output={}", output));
    Ok((flags, baseline_path))
}

/// Collects the enabled tests, accumulating them as datatest requirements.
/// We collect the test data sources ourselves instead of letting datatest
/// do it because we want to select them based on enabled feature as indicated
/// in the source. We still use datatest to finally run the tests to utilize its
/// execution engine.
fn collect_enabled_tests(reqs: &mut Vec<Requirements>, group: &str, feature: &Feature, path: &str) {
    let mut p = PathBuf::new();
    p.push(path);
    for e in WalkDir::new(p.clone()).min_depth(1).into_iter() {
        if let Ok(entry) = e {
            if !entry.file_name().to_string_lossy().ends_with(".move") {
                continue;
            }
            let path = entry.path();
            let mut included = match feature.inclusion_mode {
                InclusionMode::Implicit => !extract_test_directives(path, "// exclude_for: ")
                    .unwrap_or_default()
                    .iter()
                    .any(|s| s.as_str() == feature.name),
                InclusionMode::Explicit => extract_test_directives(path, "// also_include_for: ")
                    .unwrap_or_default()
                    .iter()
                    .any(|s| s.as_str() == feature.name),
            };
            if included && read_env_var(ENV_TEST_ON_CI) == "1" {
                included = feature.enable_in_ci
                    && extract_test_directives(path, "// no_ci:")
                        .unwrap_or_default()
                        .is_empty();
            }
            if included {
                reqs.push(Requirements::new(
                    feature.runner,
                    format!("prover {}[{}]", group, feature.name),
                    p.to_string_lossy().to_string(),
                    path.to_string_lossy().to_string(),
                ));
            }
        }
    }
}

// Test entry point based on datatest runner.
fn main() {
    let mut reqs = vec![];
    for feature in TESTED_FEATURES {
        // Evaluate whether the user narrowed which feature to test.
        let feature_narrow = read_env_var(ENV_TEST_FEATURE);
        if !feature_narrow.is_empty() && feature.name != feature_narrow {
            continue;
        }
        // Check whether we are running extended tests
        if read_env_var(ENV_TEST_EXTENDED) == "1" {
            collect_enabled_tests(&mut reqs, "extended", feature, "tests/xsources");
        } else {
            collect_enabled_tests(&mut reqs, "unit", feature, "tests/sources");
            collect_enabled_tests(&mut reqs, "stdlib", feature, "../move-stdlib");
            collect_enabled_tests(&mut reqs, "diem", feature, "../diem-framework");
        }
    }
    datatest_stable::runner(&reqs);
}
<commit_msg>[move-prover] Streamline builtin functions for vectors.<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use std::path::{Path, PathBuf};

use codespan_reporting::term::termcolor::Buffer;

use anyhow::anyhow;
use itertools::Itertools;
use move_prover::{cli::Options, run_move_prover};
use move_prover_test_utils::{
    baseline_test::verify_or_update_baseline, extract_test_directives, read_env_var,
};
use tempfile::TempDir;

use datatest_stable::Requirements;
#[allow(unused_imports)]
use log::{debug, info, warn};
use std::sync::atomic::{AtomicBool, Ordering};
use walkdir::WalkDir;

const ENV_FLAGS: &str = "MVP_TEST_FLAGS";
const ENV_TEST_EXTENDED: &str = "MVP_TEST_X";
const ENV_TEST_INCONSISTENCY: &str = "MVP_TEST_INCONSISTENCY";
const ENV_TEST_FEATURE: &str = "MVP_TEST_FEATURE";
const ENV_TEST_ON_CI: &str = "MVP_TEST_ON_CI";
const INCONSISTENCY_TEST_FLAGS: &[&str] = &[
    "--dependency=../move-stdlib/modules",
    "--dependency=../diem-framework/modules",
    "--check-inconsistency",
];
const REGULAR_TEST_FLAGS: &[&str] = &[
    "--dependency=../move-stdlib/modules",
    "--dependency=../diem-framework/modules",
];

static NOT_CONFIGURED_WARNED: AtomicBool = AtomicBool::new(false);

/// A struct to describe a feature to test.
struct Feature {
    /// Name of this feature.
    name: &'static str,
    /// Flags specific to this feature.
    flags: &'static [&'static str],
    /// Inclusion mode.
    inclusion_mode: InclusionMode,
    /// Whether this feature will be tested in CI.
    enable_in_ci: bool,
    /// Whether this feature has as a separate baseline file.
    separate_baseline: bool,
    /// A static function pointer to the runner to be used for datatest. Since datatest
    /// does not support function values and closures, we need to have a different runner for
    /// each feature
    runner: fn(&Path) -> datatest_stable::Result<()>,
}

/// An inclusion mode. A feature may be run in one of these modes.
#[derive(Clone, Copy)]
enum InclusionMode {
    /// Only a test which has the comment `// also_include_for: <feature>` will be included.
    Explicit,
    /// Every test will be included unless it has the comment `// exclude_for: <feature>`.
    Implicit,
}

const TESTED_FEATURES: &[Feature] = &[
    Feature {
        name: "default",
        flags: &[],
        inclusion_mode: InclusionMode::Implicit,
        enable_in_ci: true,
        separate_baseline: false,
        runner: runner_default,
    },
    /* Deactivated ror now as the baseline output is unstable. Calling cvc4 produces errors
       because of a protocol issue Boogie to CVC4, and the errors reported from this appear
       to be unstable.
    Feature {
        name: "cvc4",
        flags: &["--use-cvc4"],
        inclusion_mode: InclusionMode::Explicit,
        enable_in_ci: false, // Do not enable in CI until boogie <-> cvc4 issues are fixed
        separate_baseline: true,
        runner: runner_cvc4,
    },
     */
];

fn get_feature_by_name(name: &str) -> &'static Feature {
    for feature in TESTED_FEATURES {
        if feature.name == name {
            return feature;
        }
    }
    panic!("feature not found")
}

fn runner_default(p: &Path) -> datatest_stable::Result<()> {
    test_runner_for_feature(p, get_feature_by_name("default"))
}
fn runner_cvc4(p: &Path) -> datatest_stable::Result<()> {
    test_runner_for_feature(p, get_feature_by_name("cvc4"))
}

/// Test runner for a given feature.
fn test_runner_for_feature(path: &Path, feature: &Feature) -> datatest_stable::Result<()> {
    // Use the below + `cargo test -- --test-threads=1` to identify a long running test
    //println!(">>> testing {}", path.to_string_lossy().to_string());

    info!(
        "testing {} with feature `{}` (flags = `{}`)",
        path.display(),
        feature.name,
        feature.flags.iter().map(|s| s.to_string()).join(" ")
    );

    let temp_dir = TempDir::new()?;
    std::fs::create_dir_all(temp_dir.path())?;
    let (mut args, baseline_path) = get_flags_and_baseline(temp_dir.path(), path, feature)?;

    args.insert(0, "mvp_test".to_owned());
    args.push("--verbose=warn".to_owned());
    // TODO: timeouts aren't handled correctly by the boogie wrapper but lead to hang. Determine
    //   reasons and reactivate.
    // args.push("--num-instances=2".to_owned()); // run two Boogie instances with different seeds
    // args.push("--sequential".to_owned());

    // Move source.
    args.push(path.to_string_lossy().to_string());

    let mut options = Options::create_from_args(&args)?;
    options.setup_logging_for_test();
    let no_tools = read_env_var("BOOGIE_EXE").is_empty()
        || !options.backend.use_cvc4 && read_env_var("Z3_EXE").is_empty()
        || options.backend.use_cvc4 && read_env_var("CVC4_EXE").is_empty();
    let baseline_valid =
        !no_tools || !extract_test_directives(path, "// no-boogie-test")?.is_empty();

    if no_tools {
        options.prover.generate_only = true;
        if NOT_CONFIGURED_WARNED
            .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
            .is_ok()
        {
            warn!(
                "Prover tools are not configured, verification tests will be skipped. \
        See https://github.com/diem/diem/tree/main/language/move-prover/doc/user/install.md \
        for instructions."
            );
        }
    }
    options.backend.check_tool_versions()?;
    options.prover.stable_test_output = true;
    options.backend.stable_test_output = true;

    let mut error_writer = Buffer::no_color();
    let mut diags = match run_move_prover(&mut error_writer, options) {
        Ok(()) => "".to_string(),
        Err(err) => format!("Move prover returns: {}\n", err),
    };
    if baseline_valid {
        if let Some(ref path) = baseline_path {
            diags += &String::from_utf8_lossy(&error_writer.into_inner()).to_string();
            verify_or_update_baseline(path.as_path(), &diags)?
        } else if !diags.is_empty() {
            return Err(anyhow!(
                "Unexpected prover output (expected none): {}{}",
                diags,
                String::from_utf8_lossy(&error_writer.into_inner())
            )
            .into());
        }
    }

    Ok(())
}

/// Returns flags and baseline file for this test run
fn get_flags_and_baseline(
    temp_dir: &Path,
    path: &Path,
    feature: &Feature,
) -> anyhow::Result<(Vec<String>, Option<PathBuf>)> {
    // Determine the way how to configure tests based on directory of the path.
    let path_str = path.to_string_lossy();

    let stdlib_test_flags = if read_env_var(ENV_TEST_INCONSISTENCY).is_empty() {
        REGULAR_TEST_FLAGS
    } else {
        INCONSISTENCY_TEST_FLAGS
    };

    let (base_flags, baseline_path) =
        if path_str.contains("diem-framework/") || path_str.contains("move-stdlib/") {
            (stdlib_test_flags, None)
        } else {
            (
                REGULAR_TEST_FLAGS,
                Some(path.with_extension(if feature.separate_baseline {
                    format!("{}_exp", feature.name)
                } else {
                    "exp".to_string()
                })),
            )
        };
    let mut flags = base_flags.iter().map(|s| (*s).to_string()).collect_vec();

    // Add flags specific to the feature.
    flags.extend(feature.flags.iter().map(|f| f.to_string()));

    // Add flags specified in the source.
    flags.extend(extract_test_directives(path, "// flag:")?);

    // Add flags specified via environment variable.
    flags.extend(shell_words::split(&read_env_var(ENV_FLAGS))?);

    // Create a temporary file for output. We inject the modifier to potentially prevent
    // any races between similar named files in different directories, as it appears TempPath
    // isn't working always.
    let base_name = format!("{}.bpl", path.file_stem().unwrap().to_str().unwrap());
    let output = temp_dir.join(base_name).to_str().unwrap().to_string();
    flags.push(format!("--output={}", output));
    Ok((flags, baseline_path))
}

/// Collects the enabled tests, accumulating them as datatest requirements.
/// We collect the test data sources ourselves instead of letting datatest
/// do it because we want to select them based on enabled feature as indicated
/// in the source. We still use datatest to finally run the tests to utilize its
/// execution engine.
fn collect_enabled_tests(reqs: &mut Vec<Requirements>, group: &str, feature: &Feature, path: &str) {
    let mut p = PathBuf::new();
    p.push(path);
    for e in WalkDir::new(p.clone()).min_depth(1).into_iter() {
        if let Ok(entry) = e {
            if !entry.file_name().to_string_lossy().ends_with(".move") {
                continue;
            }
            let path = entry.path();
            let mut included = match feature.inclusion_mode {
                InclusionMode::Implicit => !extract_test_directives(path, "// exclude_for: ")
                    .unwrap_or_default()
                    .iter()
                    .any(|s| s.as_str() == feature.name),
                InclusionMode::Explicit => extract_test_directives(path, "// also_include_for: ")
                    .unwrap_or_default()
                    .iter()
                    .any(|s| s.as_str() == feature.name),
            };
            if included && read_env_var(ENV_TEST_ON_CI) == "1" {
                included = feature.enable_in_ci
                    && extract_test_directives(path, "// no_ci:")
                        .unwrap_or_default()
                        .is_empty();
            }
            if included {
                reqs.push(Requirements::new(
                    feature.runner,
                    format!("prover {}[{}]", group, feature.name),
                    p.to_string_lossy().to_string(),
                    path.to_string_lossy().to_string(),
                ));
            }
        }
    }
}

// Test entry point based on datatest runner.
fn main() {
    let mut reqs = vec![];
    for feature in TESTED_FEATURES {
        // Evaluate whether the user narrowed which feature to test.
        let feature_narrow = read_env_var(ENV_TEST_FEATURE);
        if !feature_narrow.is_empty() && feature.name != feature_narrow {
            continue;
        }
        // Check whether we are running extended tests
        if read_env_var(ENV_TEST_EXTENDED) == "1" {
            collect_enabled_tests(&mut reqs, "extended", feature, "tests/xsources");
        } else {
            collect_enabled_tests(&mut reqs, "unit", feature, "tests/sources");
            collect_enabled_tests(&mut reqs, "stdlib", feature, "../move-stdlib");
            collect_enabled_tests(&mut reqs, "diem", feature, "../diem-framework");
        }
    }
    datatest_stable::runner(&reqs);
}
<|endoftext|>


<commit_before>extern crate cc;
extern crate pkg_config;

use std::env;
use std::path::PathBuf;

fn main() {
    // Find and link OpenEXR and IlmBase
    let include_paths = {
        let mut include_paths = Vec::new();

        let suffix = if let Ok(v) = env::var("OPENEXR_LIB_SUFFIX") {
            format!("-{}", v)
        } else {
            "".into()
        };

        if let Ok(path) = env::var("OPENEXR_DIR") {
            // There's an environment variable, so let's use that
            println!("cargo:rustc-link-search=native={}/lib", path);
            println!("cargo:rustc-link-lib=static=IlmImf{}", suffix);
            println!("cargo:rustc-link-lib=static=IlmImfUtil{}", suffix);
            include_paths.push(PathBuf::from(&format!("{}/include/OpenEXR", path)));
        } else {
            // There's no enviroment variable, so use pkgconfig to find
            // the libs
            // Note that if OpenEXR's version < 2.5.2, then the name of
            // pkgconfig file should be "IlmBase.pc", otherwise it will
            // be "OpenEXR.pc"
            let mut openexr_pkg_config = pkg_config::Config::new()
                .atleast_version("2.5.2")
                .probe("OpenEXR");

            if (!openexr_pkg_config.is_ok()) {
                openexr_pkg_config = pkg_config::Config::new()
                    .atleast_version("2.0.0")
                    .probe("IlmBase");
            }

            let openexr_library_paths = openexr_pkg_config
                .map(|openexr_cfg| openexr_cfg.include_paths.clone())
                .map_err(|err| {
                    panic!(
                        "couldn't find OpenEXR: environment variable \
                         OPENEXR_DIR is unset and pkg-config failed: {}",
                        err
                    )
                })
                .unwrap();

            include_paths.extend_from_slice(&openexr_library_paths);
        }

        if let Ok(path) = env::var("ILMBASE_DIR") {
            println!("cargo:rustc-link-search=native={}/lib", path);
            println!("cargo:rustc-link-lib=static=IexMath{}", suffix);
            println!("cargo:rustc-link-lib=static=Iex{}", suffix);
            println!("cargo:rustc-link-lib=static=Imath{}", suffix);
            println!("cargo:rustc-link-lib=static=IlmThread{}", suffix);
            println!("cargo:rustc-link-lib=static=Half");
            include_paths.push(PathBuf::from(&format!("{}/include/OpenEXR", path)));
        } else {
            let paths = pkg_config::Config::new()
                .atleast_version("2.0.0")
                .cargo_metadata(false) // OpenEXR already pulls in all the flags we need
                .probe("IlmBase")
                .map(|ilmbase_cfg| ilmbase_cfg.include_paths.clone())
                .map_err(|err| {
                    panic!(
                        "couldn't find IlmBase: environment variable \
                         ILMBASE_DIR is unset and pkg-config failed: {}",
                        err
                    )
                })
                .unwrap();
            include_paths.extend_from_slice(&paths);
        }

        include_paths
    };

    // Find and link zlib, needed for OpenEXR
    // Use environment variable if it exists, and otherwise use pkgconfig.
    if let Ok(path) = env::var("ZLIB_DIR") {
        println!("cargo:rustc-link-search=native={}/lib", path);
        println!("cargo:rustc-link-lib=static=zlibstatic");
    } else if let Err(err) = pkg_config::probe_library("zlib") {
        panic!(
            "couldn't find zlib: environment variable ZLIB_DIR is unset \
             and pkg-config failed: {}",
            err
        );
    }

    // Build C wrapper for OpenEXR
    let mut cc = cc::Build::new();
    cc.cpp(true).include("c_wrapper");
    #[cfg(target_env = "msvc")]
    cc.flag("/std:c++14");
    #[cfg(not(target_env = "msvc"))]
    cc.flag("-std=c++0x");
    for path in &include_paths {
        cc.include(path);
    }
    cc.file("c_wrapper/cexr.cpp")
        .file("c_wrapper/rust_istream.cpp")
        .file("c_wrapper/memory_istream.cpp")
        .file("c_wrapper/rust_ostream.cpp")
        .compile("libcexr.a");
}
<commit_msg>Fix issues with pkg-config finding OpenEXR.<commit_after>extern crate cc;
extern crate pkg_config;

use std::env;
use std::path::PathBuf;

fn main() {
    // Find and link OpenEXR and IlmBase
    let include_paths = {
        let mut include_paths = Vec::new();

        let suffix = if let Ok(v) = env::var("OPENEXR_LIB_SUFFIX") {
            format!("-{}", v)
        } else {
            "".into()
        };

        if let Ok(path) = env::var("OPENEXR_DIR") {
            // There's an environment variable, so let's use that
            println!("cargo:rustc-link-search=native={}/lib", path);
            println!("cargo:rustc-link-lib=static=IlmImf{}", suffix);
            println!("cargo:rustc-link-lib=static=IlmImfUtil{}", suffix);
            include_paths.push(PathBuf::from(&format!("{}/include/OpenEXR", path)));
        } else {
            // There's no enviroment variable, so use pkgconfig to find
            // the libs.
            let paths = pkg_config::Config::new()
                .atleast_version("2.0.0")
                .probe("OpenEXR")
                .map(|openexr_cfg| openexr_cfg.include_paths.clone())
                .map_err(|err| {
                    panic!(
                        "couldn't find OpenEXR: environment variable \
                         OPENEXR_DIR is unset and pkg-config failed: {}",
                        err
                    )
                })
                .unwrap();

            include_paths.extend_from_slice(&paths);
        }

        if let Ok(path) = env::var("ILMBASE_DIR") {
            println!("cargo:rustc-link-search=native={}/lib", path);
            println!("cargo:rustc-link-lib=static=IexMath{}", suffix);
            println!("cargo:rustc-link-lib=static=Iex{}", suffix);
            println!("cargo:rustc-link-lib=static=Imath{}", suffix);
            println!("cargo:rustc-link-lib=static=IlmThread{}", suffix);
            println!("cargo:rustc-link-lib=static=Half");
            include_paths.push(PathBuf::from(&format!("{}/include/OpenEXR", path)));
        } else {
            // There's no enviroment variable, so use pkgconfig to find
            // the libs.
            let paths = pkg_config::Config::new()
                .atleast_version("2.0.0")
                .cargo_metadata(false) // OpenEXR already pulls in all the flags we need
                .probe("IlmBase")
                .map(|ilmbase_cfg| ilmbase_cfg.include_paths.clone())
                .map_err(|err| {
                    panic!(
                        "couldn't find IlmBase: environment variable \
                         ILMBASE_DIR is unset and pkg-config failed: {}",
                        err
                    )
                })
                .unwrap();
            include_paths.extend_from_slice(&paths);
        }

        include_paths
    };

    // Find and link zlib, needed for OpenEXR
    // Use environment variable if it exists, and otherwise use pkgconfig.
    if let Ok(path) = env::var("ZLIB_DIR") {
        println!("cargo:rustc-link-search=native={}/lib", path);
        println!("cargo:rustc-link-lib=static=zlibstatic");
    } else if let Err(err) = pkg_config::probe_library("zlib") {
        panic!(
            "couldn't find zlib: environment variable ZLIB_DIR is unset \
             and pkg-config failed: {}",
            err
        );
    }

    // Build C wrapper for OpenEXR
    let mut cc = cc::Build::new();
    cc.cpp(true).include("c_wrapper");
    #[cfg(target_env = "msvc")]
    cc.flag("/std:c++14");
    #[cfg(not(target_env = "msvc"))]
    cc.flag("-std=c++0x");
    for path in &include_paths {
        cc.include(path);
    }
    cc.file("c_wrapper/cexr.cpp")
        .file("c_wrapper/rust_istream.cpp")
        .file("c_wrapper/memory_istream.cpp")
        .file("c_wrapper/rust_ostream.cpp")
        .compile("libcexr.a");
}
<|endoftext|>


<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// ignore-fast

#[feature(asm)];

use std::io::Process;
use std::os;
use std::str;

// lifted from the test module
pub fn black_box<T>(dummy: T) { unsafe { asm!("" : : "r"(&dummy)) } }

fn silent_recurse() {
    let buf = [0, ..1000];
    black_box(buf);
    silent_recurse();
}

fn loud_recurse() {
    println!("hello!");
    loud_recurse();
    black_box(()); // don't optimize this into a tail call. please.
}

fn main() {
    let args = os::args();
    if args.len() > 1 && args[1].as_slice() == "silent" {
        silent_recurse();
    } else if args.len() > 1 && args[1].as_slice() == "loud" {
        loud_recurse();
    } else {
        let silent = Process::output(args[0], [~"silent"]).unwrap();
        assert!(!silent.status.success());
        let error = str::from_utf8_lossy(silent.error);
        assert!(error.as_slice().contains("has overflowed its stack"));

        let loud = Process::output(args[0], [~"loud"]).unwrap();
        assert!(!loud.status.success());
        let error = str::from_utf8_lossy(silent.error);
        assert!(error.as_slice().contains("has overflowed its stack"));
    }
}
<commit_msg>test: avoid infinite loop in out-of-stack.rs<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// ignore-fast

#[feature(asm)];

use std::io::Process;
use std::os;
use std::str;

// lifted from the test module
// Inlining to avoid llvm turning the recursive functions into tail calls,
// which doesn't consume stack.
#[inline(always)]
pub fn black_box<T>(dummy: T) { unsafe { asm!("" : : "r"(&dummy)) } }

fn silent_recurse() {
    let buf = [0, ..1000];
    black_box(buf);
    silent_recurse();
}

fn loud_recurse() {
    println!("hello!");
    loud_recurse();
    black_box(()); // don't optimize this into a tail call. please.
}

fn main() {
    let args = os::args();
    if args.len() > 1 && args[1].as_slice() == "silent" {
        silent_recurse();
    } else if args.len() > 1 && args[1].as_slice() == "loud" {
        loud_recurse();
    } else {
        let silent = Process::output(args[0], [~"silent"]).unwrap();
        assert!(!silent.status.success());
        let error = str::from_utf8_lossy(silent.error);
        assert!(error.as_slice().contains("has overflowed its stack"));

        let loud = Process::output(args[0], [~"loud"]).unwrap();
        assert!(!loud.status.success());
        let error = str::from_utf8_lossy(silent.error);
        assert!(error.as_slice().contains("has overflowed its stack"));
    }
}
<|endoftext|>


<commit_before>// build-fail
// ignore-tidy-linelength
// revisions: legacy v0
//[legacy]compile-flags: -Z symbol-mangling-version=legacy
    //[v0]compile-flags: -Z symbol-mangling-version=v0
//[legacy]normalize-stderr-32-bit: "hdb62078998ce7ea8" -> "SYMBOL_HASH"
//[legacy]normalize-stderr-64bit: "h62e540f14f879d56" -> "SYMBOL_HASH"

#![feature(optin_builtin_traits, rustc_attrs)]
#![allow(dead_code)]

mod foo {
    pub struct Foo { x: u32 }

    impl Foo {
        #[rustc_symbol_name]
        //[legacy]~^ ERROR symbol-name(_ZN5impl13foo3Foo3bar
        //[legacy]~| ERROR demangling(impl1::foo::Foo::bar
        //[legacy]~| ERROR demangling-alt(impl1::foo::Foo::bar)
         //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13fooNtB2_3Foo3bar)
            //[v0]~| ERROR demangling(<impl1[317d481089b8c8fe]::foo::Foo>::bar)
            //[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::bar)
        #[rustc_def_path]
        //[legacy]~^ ERROR def-path(foo::Foo::bar)
           //[v0]~^^ ERROR def-path(foo::Foo::bar)
        fn bar() { }
    }
}

mod bar {
    use foo::Foo;

    impl Foo {
        #[rustc_symbol_name]
        //[legacy]~^ ERROR symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz
        //[legacy]~| ERROR demangling(impl1::bar::<impl impl1::foo::Foo>::baz
        //[legacy]~| ERROR demangling-alt(impl1::bar::<impl impl1::foo::Foo>::baz)
         //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13barNtNtB4_3foo3Foo3baz)
            //[v0]~| ERROR demangling(<impl1[317d481089b8c8fe]::foo::Foo>::baz)
            //[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::baz)
        #[rustc_def_path]
        //[legacy]~^ ERROR def-path(bar::<impl foo::Foo>::baz)
           //[v0]~^^ ERROR def-path(bar::<impl foo::Foo>::baz)
        fn baz() { }
    }
}

trait Foo {
    type Assoc;
}

auto trait AutoTrait {}

fn main() {
    // Test closure mangling, and disambiguators.
    || {};
    || {
        trait Bar {
            fn method(&self) {}
        }

        // Test type mangling, by putting them in an `impl` header.
        impl Bar for [&'_ (dyn Foo<Assoc = extern fn(&u8, ...)> + AutoTrait); 3] {
            #[rustc_symbol_name]
            //[legacy]~^ ERROR symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$3$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method
            //[legacy]~| ERROR demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method
            //[legacy]~| ERROR demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method)
             //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs4fqI2P2rA04_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
                //[v0]~| ERROR demangling(<[&dyn impl1[317d481089b8c8fe]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[317d481089b8c8fe]::AutoTrait; 3: usize] as impl1[317d481089b8c8fe]::main::{closure#1}::Bar>::method)
                //[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
            #[rustc_def_path]
            //[legacy]~^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{{closure}}#1::Bar>::method)
               //[v0]~^^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{{closure}}#1::Bar>::method)
            fn method(&self) {}
        }
    };
}
<commit_msg>Fix normalizing 32bit symbol hash.<commit_after>// build-fail
// ignore-tidy-linelength
// revisions: legacy v0
//[legacy]compile-flags: -Z symbol-mangling-version=legacy
    //[v0]compile-flags: -Z symbol-mangling-version=v0
//[legacy]normalize-stderr-32bit: "hdb62078998ce7ea8" -> "SYMBOL_HASH"
//[legacy]normalize-stderr-64bit: "h62e540f14f879d56" -> "SYMBOL_HASH"

#![feature(optin_builtin_traits, rustc_attrs)]
#![allow(dead_code)]

mod foo {
    pub struct Foo { x: u32 }

    impl Foo {
        #[rustc_symbol_name]
        //[legacy]~^ ERROR symbol-name(_ZN5impl13foo3Foo3bar
        //[legacy]~| ERROR demangling(impl1::foo::Foo::bar
        //[legacy]~| ERROR demangling-alt(impl1::foo::Foo::bar)
         //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13fooNtB2_3Foo3bar)
            //[v0]~| ERROR demangling(<impl1[317d481089b8c8fe]::foo::Foo>::bar)
            //[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::bar)
        #[rustc_def_path]
        //[legacy]~^ ERROR def-path(foo::Foo::bar)
           //[v0]~^^ ERROR def-path(foo::Foo::bar)
        fn bar() { }
    }
}

mod bar {
    use foo::Foo;

    impl Foo {
        #[rustc_symbol_name]
        //[legacy]~^ ERROR symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz
        //[legacy]~| ERROR demangling(impl1::bar::<impl impl1::foo::Foo>::baz
        //[legacy]~| ERROR demangling-alt(impl1::bar::<impl impl1::foo::Foo>::baz)
         //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13barNtNtB4_3foo3Foo3baz)
            //[v0]~| ERROR demangling(<impl1[317d481089b8c8fe]::foo::Foo>::baz)
            //[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::baz)
        #[rustc_def_path]
        //[legacy]~^ ERROR def-path(bar::<impl foo::Foo>::baz)
           //[v0]~^^ ERROR def-path(bar::<impl foo::Foo>::baz)
        fn baz() { }
    }
}

trait Foo {
    type Assoc;
}

auto trait AutoTrait {}

fn main() {
    // Test closure mangling, and disambiguators.
    || {};
    || {
        trait Bar {
            fn method(&self) {}
        }

        // Test type mangling, by putting them in an `impl` header.
        impl Bar for [&'_ (dyn Foo<Assoc = extern fn(&u8, ...)> + AutoTrait); 3] {
            #[rustc_symbol_name]
            //[legacy]~^ ERROR symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$3$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method
            //[legacy]~| ERROR demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method
            //[legacy]~| ERROR demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method)
             //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs4fqI2P2rA04_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
                //[v0]~| ERROR demangling(<[&dyn impl1[317d481089b8c8fe]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[317d481089b8c8fe]::AutoTrait; 3: usize] as impl1[317d481089b8c8fe]::main::{closure#1}::Bar>::method)
                //[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
            #[rustc_def_path]
            //[legacy]~^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{{closure}}#1::Bar>::method)
               //[v0]~^^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{{closure}}#1::Bar>::method)
            fn method(&self) {}
        }
    };
}
<|endoftext|>


<commit_before>use std::vec::Vec;
use std::boxed::Box;

use sql::tokenizer::Tokenizer;

#[test]
fn test_one_word_in_line() {
    let tokens = vec!["one"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    let actual = t.next();
    assert!(actual.is_some());
}

fn build_tokens_string<'a>(tokens: &Vec<&'a str>) -> Box<String> {
    let mut s = "".to_string();
    for &token in (*tokens).iter() {
        s = s + token;
    }
    Box::new(s)
}

#[test]
fn test_one_word_with_first_and_last_same_char() {
    let tokens = vec!["eone"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}

#[test]
fn test_simple_whitespace_delimeter() {
    let tokens = vec!["one", " ", "two"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}

fn test_tokens<'a>(expected_tokens: &Vec<&'a str>, actual_tokens: &mut Tokenizer<'a>) {
    for &expected in (*expected_tokens).iter() {
        let actual = actual_tokens.next();
        match actual {
            Some(v) => assert_eq!(v, expected),
            None => assert!(expected == ""),
        }
    }
}

#[test]
fn test_simple_tabulation_delimeter() {
    let tokens = vec!["one", "\t", "two"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}

#[test]
fn test_simple_new_line_delimeter() {
    let tokens = vec!["one", "\n", "two"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}

#[test]
fn test_end_of_line_as_none() {
    let tokens = vec!["one", "\n", "two", ""];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}

#[test]
fn test_whitespaces_as_one_token() {
    let tokens = vec!["one", " \t \n ", "two"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}

#[test]
fn test_exclamation_mark() {
    let tokens = vec!["one", "!", "two"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}
<commit_msg>add test for white spaces delimited by special symbols<commit_after>use std::vec::Vec;
use std::boxed::Box;

use sql::tokenizer::Tokenizer;

#[test]
fn test_one_word_in_line() {
    let tokens = vec!["one"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    let actual = t.next();
    assert!(actual.is_some());
}

fn build_tokens_string<'a>(tokens: &Vec<&'a str>) -> Box<String> {
    let mut s = "".to_string();
    for &token in (*tokens).iter() {
        s = s + token;
    }
    Box::new(s)
}

#[test]
fn test_one_word_with_first_and_last_same_char() {
    let tokens = vec!["eone"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}

#[test]
fn test_simple_whitespace_delimeter() {
    let tokens = vec!["one", " ", "two"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}

fn test_tokens<'a>(expected_tokens: &Vec<&'a str>, actual_tokens: &mut Tokenizer<'a>) {
    for &expected in (*expected_tokens).iter() {
        let actual = actual_tokens.next();
        match actual {
            Some(v) => assert_eq!(v, expected),
            None => assert!(expected == ""),
        }
    }
}

#[test]
fn test_simple_tabulation_delimeter() {
    let tokens = vec!["one", "\t", "two"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}

#[test]
fn test_simple_new_line_delimeter() {
    let tokens = vec!["one", "\n", "two"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}

#[test]
fn test_end_of_line_as_none() {
    let tokens = vec!["one", "\n", "two", ""];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}

#[test]
fn test_whitespaces_as_one_token() {
    let tokens = vec!["one", " \t \n ", "two"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}

#[test]
fn test_exclamation_mark() {
    let tokens = vec!["one", "!", "two"];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}

#[test]
fn test_white_spaces_delimited_with_special_char() {
    let tokens = vec![" \n\t", "!", "\n "];
    let token_string = build_tokens_string(&tokens);
    let mut t = Tokenizer::new(&(*token_string));
    test_tokens(&tokens, &mut t);
}
<|endoftext|>


<commit_before>use std::io::{self, Read, Seek, SeekFrom};
use std::result::Result as StdResult;
use std::str::{from_utf8, Utf8Error};
use std::cmp::min;
use byteorder::{ReadBytesExt, BigEndian as BE};
use imagelib::{png, Rgba, ImageBuffer, ColorType};
use {Run, Image, RealTime, TimeSpan, Time, Segment};

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Utf8(err: Utf8Error) {
            from()
        }
        Io(err: io::Error) {
            from()
        }
    }
}

pub type Result<T> = StdResult<T, Error>;

fn to_time(milliseconds: u64) -> Time {
    if milliseconds == 0 {
        Time::default()
    } else {
        RealTime(Some(TimeSpan::from_milliseconds(milliseconds as f64))).into()
    }
}

fn read_string<R: Read>(mut source: R, buf: &mut Vec<u8>) -> Result<&str> {
    let str_length = source.read_u16::<BE>()? as usize;
    buf.reserve(str_length);
    unsafe { buf.set_len(str_length) };
    source.read_exact(buf)?;
    from_utf8(buf).map_err(Into::into)
}

pub fn parse<R: Read + Seek>(mut source: R) -> Result<Run> {
    let mut run = Run::new();
    let mut buf = Vec::new();
    let mut buf2 = Vec::new();

    // Skip to the goal string
    source.seek(SeekFrom::Start(0xc5))?;
    run.set_category_name(read_string(&mut source, &mut buf)?);

    // Skip to the title string
    source.read_u8()?;
    run.set_game_name(read_string(&mut source, &mut buf)?);

    source.seek(SeekFrom::Current(0x6))?;
    let segment_count = source.read_u32::<BE>()?;

    // The object header changes if there is no instance of one of the object used by the Run class.
    // The 2 objects that can be affected are the Time object and the ImageIcon object.
    // The next step of the import algorithm is to check for their presence.
    let (mut time_encountered, mut icon_encountered) = (false, false);

    let mut aggregate_time_ms = 0;

    // Seek to the first byte of the first segment
    source.seek(SeekFrom::Current(0x8F))?;
    for _ in 0..segment_count {
        let mut icon = None;
        let mut best_segment_ms = 0;

        let id = source.read_u8()?;
        if id != 0x70 {
            if !time_encountered {
                time_encountered = true;

                // Seek past the object declaration
                source.seek(SeekFrom::Current(0x36))?;
            } else {
                source.seek(SeekFrom::Current(0x5))?;
            }

            best_segment_ms = source.read_u64::<BE>()?;
        }

        let id = source.read_u8()?;
        if id != 0x70 {
            let seek_offset_base = if !icon_encountered {
                icon_encountered = true;
                source.seek(SeekFrom::Current(0xBC))?;
                0x25
            } else {
                source.seek(SeekFrom::Current(0x5))?;
                0x18
            };
            let height = source.read_u32::<BE>()?;
            let width = source.read_u32::<BE>()?;

            source.seek(SeekFrom::Current(seek_offset_base))?;

            let len = width as usize * height as usize * 4;
            buf.reserve(min(len, 32 << 20));
            unsafe { buf.set_len(len) };
            source.read_exact(&mut buf)?;

            if let Some(image) = ImageBuffer::<Rgba<_>, _>::from_raw(
                width,
                height,
                buf.as_slice(),
            )
            {
                buf2.clear();
                if png::PNGEncoder::new(&mut buf2)
                    .encode(image.as_ref(), width, height, ColorType::RGBA(8))
                    .is_ok()
                {
                    icon = Some(Image::new(&buf2));
                }
            }
        }

        // Skip to the segment name
        source.read_u8()?;
        let mut segment = Segment::new(read_string(&mut source, &mut buf)?);

        if let Some(icon) = icon {
            segment.set_icon(icon);
        }

        // Read the segment time
        let id = source.read_u8()?;
        let segment_time_ms = match id {
            0x71 => {
                source.seek(SeekFrom::Current(0x4))?;
                best_segment_ms
            }
            0x70 => 0,
            _ => {
                // Since there is always a best segment when there is a best time in Llanfair,
                // I assume that there will never be another Time object declaration before this data.
                source.seek(SeekFrom::Current(0x5))?;
                source.read_u64::<BE>()?
            }
        };

        if segment_time_ms != 0 {
            aggregate_time_ms += segment_time_ms;
            let split_time = to_time(aggregate_time_ms);
            segment.set_personal_best_split_time(split_time);
        }

        segment.set_best_segment_time(to_time(best_segment_ms));

        run.push_segment(segment);

        // Seek to the beginning of the next segment name
        source.seek(SeekFrom::Current(0x6))?;
    }

    Ok(run)
}
<commit_msg>Fix Out of Memory in LLanfair Parser<commit_after>use std::io::{self, Read, Seek, SeekFrom};
use std::result::Result as StdResult;
use std::str::{from_utf8, Utf8Error};
use byteorder::{ReadBytesExt, BigEndian as BE};
use imagelib::{png, Rgba, ImageBuffer, ColorType};
use {Run, Image, RealTime, TimeSpan, Time, Segment};

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        LengthOutOfBounds {}
        Utf8(err: Utf8Error) {
            from()
        }
        Io(err: io::Error) {
            from()
        }
    }
}

pub type Result<T> = StdResult<T, Error>;

fn to_time(milliseconds: u64) -> Time {
    if milliseconds == 0 {
        Time::default()
    } else {
        RealTime(Some(TimeSpan::from_milliseconds(milliseconds as f64))).into()
    }
}

fn read_string<R: Read>(mut source: R, buf: &mut Vec<u8>, max_length: u64) -> Result<&str> {
    let str_length = source.read_u16::<BE>()? as usize;
    if str_length as u64 > max_length {
        return Err(Error::LengthOutOfBounds);
    }
    buf.clear();
    buf.reserve(str_length);
    unsafe { buf.set_len(str_length) };
    source.read_exact(buf)?;
    from_utf8(buf).map_err(Into::into)
}

pub fn parse<R: Read + Seek>(mut source: R) -> Result<Run> {
    let mut run = Run::new();
    let mut buf = Vec::new();
    let mut buf2 = Vec::new();

    // Determine total length of the source
    let total_len = source.seek(SeekFrom::End(0))?;

    // Skip to the goal string
    source.seek(SeekFrom::Start(0xc5))?;
    run.set_category_name(read_string(&mut source, &mut buf, total_len)?);

    // Skip to the title string
    source.read_u8()?;
    run.set_game_name(read_string(&mut source, &mut buf, total_len)?);

    source.seek(SeekFrom::Current(0x6))?;
    let segment_count = source.read_u32::<BE>()?;

    // The object header changes if there is no instance of one of the object used by the Run class.
    // The 2 objects that can be affected are the Time object and the ImageIcon object.
    // The next step of the import algorithm is to check for their presence.
    let (mut time_encountered, mut icon_encountered) = (false, false);

    let mut aggregate_time_ms = 0;

    // Seek to the first byte of the first segment
    source.seek(SeekFrom::Current(0x8F))?;
    for _ in 0..segment_count {
        let mut icon = None;
        let mut best_segment_ms = 0;

        let id = source.read_u8()?;
        if id != 0x70 {
            if !time_encountered {
                time_encountered = true;

                // Seek past the object declaration
                source.seek(SeekFrom::Current(0x36))?;
            } else {
                source.seek(SeekFrom::Current(0x5))?;
            }

            best_segment_ms = source.read_u64::<BE>()?;
        }

        let id = source.read_u8()?;
        if id != 0x70 {
            let seek_offset_base = if !icon_encountered {
                icon_encountered = true;
                source.seek(SeekFrom::Current(0xBC))?;
                0x25
            } else {
                source.seek(SeekFrom::Current(0x5))?;
                0x18
            };
            let height = source.read_u32::<BE>()?;
            let width = source.read_u32::<BE>()?;

            source.seek(SeekFrom::Current(seek_offset_base))?;

            let len = (width as usize)
                .checked_mul(height as usize)
                .and_then(|b| b.checked_mul(4))
                .ok_or(Error::LengthOutOfBounds)?;

            if len as u64 > total_len || width == 0 || height == 0 {
                return Err(Error::LengthOutOfBounds);
            }

            buf.clear();
            buf.reserve(len);
            unsafe { buf.set_len(len) };
            source.read_exact(&mut buf)?;

            if let Some(image) = ImageBuffer::<Rgba<_>, _>::from_raw(
                width,
                height,
                buf.as_slice(),
            )
            {
                buf2.clear();
                if png::PNGEncoder::new(&mut buf2)
                    .encode(image.as_ref(), width, height, ColorType::RGBA(8))
                    .is_ok()
                {
                    icon = Some(Image::new(&buf2));
                }
            }
        }

        // Skip to the segment name
        source.read_u8()?;
        let mut segment = Segment::new(read_string(&mut source, &mut buf, total_len)?);

        if let Some(icon) = icon {
            segment.set_icon(icon);
        }

        // Read the segment time
        let id = source.read_u8()?;
        let segment_time_ms = match id {
            0x71 => {
                source.seek(SeekFrom::Current(0x4))?;
                best_segment_ms
            }
            0x70 => 0,
            _ => {
                // Since there is always a best segment when there is a best time in Llanfair,
                // I assume that there will never be another Time object declaration before this data.
                source.seek(SeekFrom::Current(0x5))?;
                source.read_u64::<BE>()?
            }
        };

        if segment_time_ms != 0 {
            aggregate_time_ms += segment_time_ms;
            let split_time = to_time(aggregate_time_ms);
            segment.set_personal_best_split_time(split_time);
        }

        segment.set_best_segment_time(to_time(best_segment_ms));

        run.push_segment(segment);

        // Seek to the beginning of the next segment name
        source.seek(SeekFrom::Current(0x6))?;
    }

    Ok(run)
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Hub
//!
//! A hub provides a way to connect components into a tree. Hubs don't store changes, but can be used with things like
//! `ComponentEndPoint` to make component results user accessible.
//!

use super::super::tree::*;
use super::component::*;
use super::bus_publisher::*;
use super::immediate_publisher::*;

///
///
///
pub struct Hub {
    ///
    /// Passes changes between components
    ///
    bus: TreeChangeBus,

    ///
    /// Components attached to this hub
    ///
    components: Vec<ComponentRef>
}

impl Hub {
    ///
    /// Creates a new hub
    ///
    pub fn new() -> Hub {
        Hub { bus: TreeChangeBus::new(), components: vec![] }
    }

    ///
    /// Returns a consumer that will read from a particular address relative to this hub
    ///
    pub fn read_from<T: ToTreeAddress>(&mut self, address: &T) -> ConsumerRef {
        unimplemented!();
    }

    ///
    /// Returns a publisher that will write to a particular address relative to this hub
    ///
    pub fn publish_to<T: ToTreeAddress>(&mut self, address: &T) -> PublisherRef {
        let publisher   = ImmediatePublisher::new();
        let consumer    = publisher.create_consumer();

        // consumer.subscribe()

        unimplemented!();
    }

    ///
    /// Attaches a component that reads from
    ///
    pub fn add_component<TComponent: ConvertToComponent, TFrom: ToTreeAddress, TTo: ToTreeAddress>(&mut self, component: TComponent, read_from: &TFrom, publish_to: &TTo) {
        let consumer    = self.read_from(read_from);
        let publisher   = self.publish_to(publish_to);

        self.components.push(component.into_component(consumer, publisher));
    }

    ///
    /// Pumps any messages waiting for this hub
    ///
    #[inline]
    pub fn pump(&mut self) {
        self.bus.pump();
    }

    ///
    /// Processes messages for this hub until there are no more to be processed
    ///
    #[inline]
    pub fn flush(&mut self) {
        self.bus.flush();
    }
}
<commit_msg>Fix comment<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Hub
//!
//! A hub provides a way to connect components into a tree. Hubs don't store changes, but can be used with things like
//! `ComponentEndPoint` to make component results user accessible.
//!

use super::super::tree::*;
use super::component::*;
use super::bus_publisher::*;
use super::immediate_publisher::*;

///
///
///
pub struct Hub {
    ///
    /// Passes changes between components
    ///
    bus: TreeChangeBus,

    ///
    /// Components attached to this hub
    ///
    components: Vec<ComponentRef>
}

impl Hub {
    ///
    /// Creates a new hub
    ///
    pub fn new() -> Hub {
        Hub { bus: TreeChangeBus::new(), components: vec![] }
    }

    ///
    /// Returns a consumer that will read from a particular address relative to this hub
    ///
    pub fn read_from<T: ToTreeAddress>(&mut self, address: &T) -> ConsumerRef {
        unimplemented!();
    }

    ///
    /// Returns a publisher that will write to a particular address relative to this hub
    ///
    pub fn publish_to<T: ToTreeAddress>(&mut self, address: &T) -> PublisherRef {
        let publisher   = ImmediatePublisher::new();
        let consumer    = publisher.create_consumer();

        let subscription = consumer.subscribe()

        unimplemented!();
    }

    ///
    /// Attaches a component that reads from a particular address and publishes its results to another
    ///
    pub fn add_component<TComponent: ConvertToComponent, TFrom: ToTreeAddress, TTo: ToTreeAddress>(&mut self, component: TComponent, read_from: &TFrom, publish_to: &TTo) {
        let consumer    = self.read_from(read_from);
        let publisher   = self.publish_to(publish_to);

        self.components.push(component.into_component(consumer, publisher));
    }

    ///
    /// Pumps any messages waiting for this hub
    ///
    #[inline]
    pub fn pump(&mut self) {
        self.bus.pump();
    }

    ///
    /// Processes messages for this hub until there are no more to be processed
    ///
    #[inline]
    pub fn flush(&mut self) {
        self.bus.flush();
    }
}
<|endoftext|>


<commit_before>#![feature(plugin_registrar, rustc_private)]

extern crate itertools;
extern crate rustc_plugin;
extern crate syntax;

use itertools::Itertools;
use rustc_plugin::Registry;
use syntax::ast::{self, Ident, TraitRef, Ty, TyKind};
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::quote::rt::Span;
use syntax::parse::{self, token, str_lit, PResult};
use syntax::parse::parser::{Parser, PathStyle};
use syntax::symbol::Symbol;
use syntax::ptr::P;
use syntax::tokenstream::{TokenTree, TokenStream};
use syntax::util::small_vector::SmallVector;

fn snake_to_camel(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.into());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.

    let mut item = match parser.parse_trait_item(&mut false) {
        Ok(s) => s,
        Err(mut diagnostic) => {
            diagnostic.emit();
            return DummyResult::any(sp);
        }
    };

    if let Err(mut diagnostic) = parser.expect(&token::Eof) {
        diagnostic.emit();
        return DummyResult::any(sp);
    }

    let old_ident = convert(&mut item.ident);

    // As far as I know, it's not possible in macro_rules! to reference an $ident in a doc string,
    // so this is the hacky workaround.
    //
    // This code looks intimidating, but it's just iterating through the trait item's attributes
    // copying non-doc attributes, and modifying doc attributes such that replacing any {} in the
    // doc string instead holds the original, snake_case ident.
    let attrs: Vec<_> = item.attrs
        .drain(..)
        .map(|mut attr| {
            if !attr.is_sugared_doc {
                return attr;
            }

            // Getting at the underlying doc comment is surprisingly painful.
            // The call-chain goes something like:
            //
            //  - https://github.com/rust-lang/rust/blob/9c15de4fd59bee290848b5443c7e194fd5afb02c/src/libsyntax/attr.rs#L283
            //  - https://github.com/rust-lang/rust/blob/9c15de4fd59bee290848b5443c7e194fd5afb02c/src/libsyntax/attr.rs#L1067
            //  - https://github.com/rust-lang/rust/blob/9c15de4fd59bee290848b5443c7e194fd5afb02c/src/libsyntax/attr.rs#L1196
            //  - https://github.com/rust-lang/rust/blob/9c15de4fd59bee290848b5443c7e194fd5afb02c/src/libsyntax/parse/mod.rs#L399
            //  - https://github.com/rust-lang/rust/blob/9c15de4fd59bee290848b5443c7e194fd5afb02c/src/libsyntax/parse/mod.rs#L268
            //
            // Note that a docstring (i.e., something with is_sugared_doc) *always* has exactly two
            // tokens: an Eq followed by a Literal, where the Literal contains a Str_. We therefore
            // match against that, modifying the inner Str with our modified Symbol.
            let mut tokens = attr.tokens.clone().into_trees();
            if let Some(tt @ TokenTree::Token(_, token::Eq)) = tokens.next() {
                let mut docstr = tokens.next().expect("Docstrings must have literal docstring");
                if let TokenTree::Token(_, token::Literal(token::Str_(ref mut doc), _)) = docstr {
                    *doc = Symbol::intern(&str_lit(&doc.as_str(), None).replace("{}", &old_ident));
                } else {
                    unreachable!();
                }
                attr.tokens = TokenStream::concat(vec![tt.into(), docstr.into()]);
            } else {
                unreachable!();
            }

            attr
        })
        .collect();
    item.attrs.extend(attrs.into_iter());

    MacEager::trait_items(SmallVector::one(item))
}

fn impl_snake_to_camel(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.into());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.

    let mut item = match parser.parse_impl_item(&mut false) {
        Ok(s) => s,
        Err(mut diagnostic) => {
            diagnostic.emit();
            return DummyResult::any(sp);
        }
    };

    if let Err(mut diagnostic) = parser.expect(&token::Eof) {
        diagnostic.emit();
        return DummyResult::any(sp);
    }

    convert(&mut item.ident);
    MacEager::impl_items(SmallVector::one(item))
}

fn ty_snake_to_camel(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.into());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.

    let mut path = match parser.parse_path(PathStyle::Type) {
        Ok(s) => s,
        Err(mut diagnostic) => {
            diagnostic.emit();
            return DummyResult::any(sp);
        }
    };

    if let Err(mut diagnostic) = parser.expect(&token::Eof) {
        diagnostic.emit();
        return DummyResult::any(sp);
    }

    // Only capitalize the final segment
    convert(&mut path.segments
                     .last_mut()
                     .unwrap()
                     .identifier);
    MacEager::ty(P(Ty {
        id: ast::DUMMY_NODE_ID,
        node: TyKind::Path(None, path),
        span: sp,
    }))
}

/// Converts an ident in-place to CamelCase and returns the previous ident.
fn convert(ident: &mut Ident) -> String {
    let ident_str = ident.to_string();
    let mut camel_ty = String::new();

    {
        // Find the first non-underscore and add it capitalized.
        let mut chars = ident_str.chars();

        // Find the first non-underscore char, uppercase it, and append it.
        // Guaranteed to succeed because all idents must have at least one non-underscore char.
        camel_ty.extend(chars.find(|&c| c != '_').unwrap().to_uppercase());

        // When we find an underscore, we remove it and capitalize the next char. To do this,
        // we need to ensure the next char is not another underscore.
        let mut chars = chars.coalesce(|c1, c2| {
            if c1 == '_' && c2 == '_' {
                Ok(c1)
            } else {
                Err((c1, c2))
            }
        });

        while let Some(c) = chars.next() {
            if c != '_' {
                camel_ty.push(c);
            } else {
                if let Some(c) = chars.next() {
                    camel_ty.extend(c.to_uppercase());
                }
            }
        }
    }

    // The Fut suffix is hardcoded right now; this macro isn't really meant to be general-purpose.
    camel_ty.push_str("Fut");

    *ident = Ident::with_empty_ctxt(Symbol::intern(&camel_ty));
    ident_str
}

trait ParseTraitRef {
    fn parse_trait_ref(&mut self) -> PResult<TraitRef>;
}

impl<'a> ParseTraitRef for Parser<'a> {
    /// Parse a::B<String,i32>
    fn parse_trait_ref(&mut self) -> PResult<TraitRef> {
        Ok(TraitRef {
            path: self.parse_path(PathStyle::Type)?,
            ref_id: ast::DUMMY_NODE_ID,
        })
    }
}

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("snake_to_camel", snake_to_camel);
    reg.register_macro("impl_snake_to_camel", impl_snake_to_camel);
    reg.register_macro("ty_snake_to_camel", ty_snake_to_camel);
}
<commit_msg>clippy: simplify else arm<commit_after>#![feature(plugin_registrar, rustc_private)]

extern crate itertools;
extern crate rustc_plugin;
extern crate syntax;

use itertools::Itertools;
use rustc_plugin::Registry;
use syntax::ast::{self, Ident, TraitRef, Ty, TyKind};
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::quote::rt::Span;
use syntax::parse::{self, token, str_lit, PResult};
use syntax::parse::parser::{Parser, PathStyle};
use syntax::symbol::Symbol;
use syntax::ptr::P;
use syntax::tokenstream::{TokenTree, TokenStream};
use syntax::util::small_vector::SmallVector;

fn snake_to_camel(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.into());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.

    let mut item = match parser.parse_trait_item(&mut false) {
        Ok(s) => s,
        Err(mut diagnostic) => {
            diagnostic.emit();
            return DummyResult::any(sp);
        }
    };

    if let Err(mut diagnostic) = parser.expect(&token::Eof) {
        diagnostic.emit();
        return DummyResult::any(sp);
    }

    let old_ident = convert(&mut item.ident);

    // As far as I know, it's not possible in macro_rules! to reference an $ident in a doc string,
    // so this is the hacky workaround.
    //
    // This code looks intimidating, but it's just iterating through the trait item's attributes
    // copying non-doc attributes, and modifying doc attributes such that replacing any {} in the
    // doc string instead holds the original, snake_case ident.
    let attrs: Vec<_> = item.attrs
        .drain(..)
        .map(|mut attr| {
            if !attr.is_sugared_doc {
                return attr;
            }

            // Getting at the underlying doc comment is surprisingly painful.
            // The call-chain goes something like:
            //
            //  - https://github.com/rust-lang/rust/blob/9c15de4fd59bee290848b5443c7e194fd5afb02c/src/libsyntax/attr.rs#L283
            //  - https://github.com/rust-lang/rust/blob/9c15de4fd59bee290848b5443c7e194fd5afb02c/src/libsyntax/attr.rs#L1067
            //  - https://github.com/rust-lang/rust/blob/9c15de4fd59bee290848b5443c7e194fd5afb02c/src/libsyntax/attr.rs#L1196
            //  - https://github.com/rust-lang/rust/blob/9c15de4fd59bee290848b5443c7e194fd5afb02c/src/libsyntax/parse/mod.rs#L399
            //  - https://github.com/rust-lang/rust/blob/9c15de4fd59bee290848b5443c7e194fd5afb02c/src/libsyntax/parse/mod.rs#L268
            //
            // Note that a docstring (i.e., something with is_sugared_doc) *always* has exactly two
            // tokens: an Eq followed by a Literal, where the Literal contains a Str_. We therefore
            // match against that, modifying the inner Str with our modified Symbol.
            let mut tokens = attr.tokens.clone().into_trees();
            if let Some(tt @ TokenTree::Token(_, token::Eq)) = tokens.next() {
                let mut docstr = tokens.next().expect("Docstrings must have literal docstring");
                if let TokenTree::Token(_, token::Literal(token::Str_(ref mut doc), _)) = docstr {
                    *doc = Symbol::intern(&str_lit(&doc.as_str(), None).replace("{}", &old_ident));
                } else {
                    unreachable!();
                }
                attr.tokens = TokenStream::concat(vec![tt.into(), docstr.into()]);
            } else {
                unreachable!();
            }

            attr
        })
        .collect();
    item.attrs.extend(attrs.into_iter());

    MacEager::trait_items(SmallVector::one(item))
}

fn impl_snake_to_camel(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.into());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.

    let mut item = match parser.parse_impl_item(&mut false) {
        Ok(s) => s,
        Err(mut diagnostic) => {
            diagnostic.emit();
            return DummyResult::any(sp);
        }
    };

    if let Err(mut diagnostic) = parser.expect(&token::Eof) {
        diagnostic.emit();
        return DummyResult::any(sp);
    }

    convert(&mut item.ident);
    MacEager::impl_items(SmallVector::one(item))
}

fn ty_snake_to_camel(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.into());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.

    let mut path = match parser.parse_path(PathStyle::Type) {
        Ok(s) => s,
        Err(mut diagnostic) => {
            diagnostic.emit();
            return DummyResult::any(sp);
        }
    };

    if let Err(mut diagnostic) = parser.expect(&token::Eof) {
        diagnostic.emit();
        return DummyResult::any(sp);
    }

    // Only capitalize the final segment
    convert(&mut path.segments
                     .last_mut()
                     .unwrap()
                     .identifier);
    MacEager::ty(P(Ty {
        id: ast::DUMMY_NODE_ID,
        node: TyKind::Path(None, path),
        span: sp,
    }))
}

/// Converts an ident in-place to CamelCase and returns the previous ident.
fn convert(ident: &mut Ident) -> String {
    let ident_str = ident.to_string();
    let mut camel_ty = String::new();

    {
        // Find the first non-underscore and add it capitalized.
        let mut chars = ident_str.chars();

        // Find the first non-underscore char, uppercase it, and append it.
        // Guaranteed to succeed because all idents must have at least one non-underscore char.
        camel_ty.extend(chars.find(|&c| c != '_').unwrap().to_uppercase());

        // When we find an underscore, we remove it and capitalize the next char. To do this,
        // we need to ensure the next char is not another underscore.
        let mut chars = chars.coalesce(|c1, c2| {
            if c1 == '_' && c2 == '_' {
                Ok(c1)
            } else {
                Err((c1, c2))
            }
        });

        while let Some(c) = chars.next() {
            if c != '_' {
                camel_ty.push(c);
            } else if let Some(c) = chars.next() {
                camel_ty.extend(c.to_uppercase());
            }
        }
    }

    // The Fut suffix is hardcoded right now; this macro isn't really meant to be general-purpose.
    camel_ty.push_str("Fut");

    *ident = Ident::with_empty_ctxt(Symbol::intern(&camel_ty));
    ident_str
}

trait ParseTraitRef {
    fn parse_trait_ref(&mut self) -> PResult<TraitRef>;
}

impl<'a> ParseTraitRef for Parser<'a> {
    /// Parse a::B<String,i32>
    fn parse_trait_ref(&mut self) -> PResult<TraitRef> {
        Ok(TraitRef {
            path: self.parse_path(PathStyle::Type)?,
            ref_id: ast::DUMMY_NODE_ID,
        })
    }
}

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("snake_to_camel", snake_to_camel);
    reg.register_macro("impl_snake_to_camel", impl_snake_to_camel);
    reg.register_macro("ty_snake_to_camel", ty_snake_to_camel);
}
<|endoftext|>


<commit_before>use std::fmt;

use anyhow::{bail, Error};

use self::parse::{Parser, RawChunk};
use super::{Graph, Node};

mod parse;

enum Chunk {
    Raw(String),
    Package,
    License,
    Repository,
    Features,
    Name,
}

pub struct Pattern(Vec<Chunk>);

impl Pattern {
    pub fn new(format: &str) -> Result<Pattern, Error> {
        let mut chunks = vec![];

        for raw in Parser::new(format) {
            let chunk = match raw {
                RawChunk::Text(text) => Chunk::Raw(text.to_owned()),
                RawChunk::Argument("p") => Chunk::Package,
                RawChunk::Argument("l") => Chunk::License,
                RawChunk::Argument("r") => Chunk::Repository,
                RawChunk::Argument("f") => Chunk::Features,
                RawChunk::Argument("lib") => Chunk::Name,
                RawChunk::Argument(a) => {
                    bail!("unsupported pattern `{}`", a);
                }
                RawChunk::Error(err) => bail!("{}", err),
            };
            chunks.push(chunk);
        }

        Ok(Pattern(chunks))
    }

    pub fn display<'a>(&'a self, graph: &'a Graph<'a>, node_index: usize) -> Display<'a> {
        Display {
            pattern: self,
            graph,
            node_index,
        }
    }
}

pub struct Display<'a> {
    pattern: &'a Pattern,
    graph: &'a Graph<'a>,
    node_index: usize,
}

impl<'a> fmt::Display for Display<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        let node = self.graph.node(self.node_index);
        match node {
            Node::Package {
                package_id,
                features,
                ..
            } => {
                let package = self.graph.package_for_id(*package_id);
                for chunk in &self.pattern.0 {
                    match chunk {
                        Chunk::Raw(s) => fmt.write_str(s)?,
                        Chunk::Package => {
                            let proc_macro_suffix = if package.proc_macro() {
                                " (proc-macro)"
                            } else {
                                ""
                            };
                            write!(
                                fmt,
                                "{} v{}{}",
                                package.name(),
                                package.version(),
                                proc_macro_suffix
                            )?;

                            let source_id = package.package_id().source_id();
                            if !source_id.is_default_registry() {
                                write!(fmt, " ({})", source_id)?;
                            }
                        }
                        Chunk::License => {
                            if let Some(license) = &package.manifest().metadata().license {
                                write!(fmt, "{}", license)?;
                            }
                        }
                        Chunk::Repository => {
                            if let Some(repository) = &package.manifest().metadata().repository {
                                write!(fmt, "{}", repository)?;
                            }
                        }
                        Chunk::Features => {
                            write!(fmt, "{}", features.join(","))?;
                        }
                        Chunk::Name => {
                            if let Some(target) = package
                                .manifest()
                                .targets()
                                .iter()
                                .find(|target| target.is_lib())
                            {
                                write!(fmt, "{}", target.name())?;
                            }
                        }
                    }
                }
            }
            Node::Feature { name, node_index } => {
                let for_node = self.graph.node(*node_index);
                match for_node {
                    Node::Package { package_id, .. } => {
                        write!(fmt, "{} feature \"{}\"", package_id.name(), name)?;
                        if self.graph.is_cli_feature(self.node_index) {
                            write!(fmt, " (command-line)")?;
                        }
                    }
                    // The node_index in Node::Feature must point to a package
                    // node, see `add_feature`.
                    _ => panic!("unexpected feature node {:?}", for_node),
                }
            }
        }

        Ok(())
    }
}
<commit_msg>Change name of enum variant to better match the formatting "character".<commit_after>use std::fmt;

use anyhow::{bail, Error};

use self::parse::{Parser, RawChunk};
use super::{Graph, Node};

mod parse;

enum Chunk {
    Raw(String),
    Package,
    License,
    Repository,
    Features,
    LibName,
}

pub struct Pattern(Vec<Chunk>);

impl Pattern {
    pub fn new(format: &str) -> Result<Pattern, Error> {
        let mut chunks = vec![];

        for raw in Parser::new(format) {
            let chunk = match raw {
                RawChunk::Text(text) => Chunk::Raw(text.to_owned()),
                RawChunk::Argument("p") => Chunk::Package,
                RawChunk::Argument("l") => Chunk::License,
                RawChunk::Argument("r") => Chunk::Repository,
                RawChunk::Argument("f") => Chunk::Features,
                RawChunk::Argument("lib") => Chunk::LibName,
                RawChunk::Argument(a) => {
                    bail!("unsupported pattern `{}`", a);
                }
                RawChunk::Error(err) => bail!("{}", err),
            };
            chunks.push(chunk);
        }

        Ok(Pattern(chunks))
    }

    pub fn display<'a>(&'a self, graph: &'a Graph<'a>, node_index: usize) -> Display<'a> {
        Display {
            pattern: self,
            graph,
            node_index,
        }
    }
}

pub struct Display<'a> {
    pattern: &'a Pattern,
    graph: &'a Graph<'a>,
    node_index: usize,
}

impl<'a> fmt::Display for Display<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        let node = self.graph.node(self.node_index);
        match node {
            Node::Package {
                package_id,
                features,
                ..
            } => {
                let package = self.graph.package_for_id(*package_id);
                for chunk in &self.pattern.0 {
                    match chunk {
                        Chunk::Raw(s) => fmt.write_str(s)?,
                        Chunk::Package => {
                            let proc_macro_suffix = if package.proc_macro() {
                                " (proc-macro)"
                            } else {
                                ""
                            };
                            write!(
                                fmt,
                                "{} v{}{}",
                                package.name(),
                                package.version(),
                                proc_macro_suffix
                            )?;

                            let source_id = package.package_id().source_id();
                            if !source_id.is_default_registry() {
                                write!(fmt, " ({})", source_id)?;
                            }
                        }
                        Chunk::License => {
                            if let Some(license) = &package.manifest().metadata().license {
                                write!(fmt, "{}", license)?;
                            }
                        }
                        Chunk::Repository => {
                            if let Some(repository) = &package.manifest().metadata().repository {
                                write!(fmt, "{}", repository)?;
                            }
                        }
                        Chunk::Features => {
                            write!(fmt, "{}", features.join(","))?;
                        }
                        Chunk::LibName => {
                            if let Some(target) = package
                                .manifest()
                                .targets()
                                .iter()
                                .find(|target| target.is_lib())
                            {
                                write!(fmt, "{}", target.name())?;
                            }
                        }
                    }
                }
            }
            Node::Feature { name, node_index } => {
                let for_node = self.graph.node(*node_index);
                match for_node {
                    Node::Package { package_id, .. } => {
                        write!(fmt, "{} feature \"{}\"", package_id.name(), name)?;
                        if self.graph.is_cli_feature(self.node_index) {
                            write!(fmt, " (command-line)")?;
                        }
                    }
                    // The node_index in Node::Feature must point to a package
                    // node, see `add_feature`.
                    _ => panic!("unexpected feature node {:?}", for_node),
                }
            }
        }

        Ok(())
    }
}
<|endoftext|>