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

use std::{
    path::{Path, PathBuf},
    sync::atomic::{AtomicBool, Ordering},
};

use anyhow::anyhow;
use codespan_reporting::term::termcolor::Buffer;
use datatest_stable::Requirements;
use itertools::Itertools;
use log::{info, warn};
use once_cell::sync::OnceCell;
use tempfile::TempDir;
use walkdir::WalkDir;

use move_command_line_common::{
    env::{read_bool_env_var, read_env_var},
    testing::EXP_EXT,
};
use move_prover::{cli::Options, run_move_prover};
use move_prover_test_utils::{baseline_test::verify_or_update_baseline, extract_test_directives};

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";

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,
    /// True if the tests should only be run if requested by MVP_TEST_FEATURE
    only_if_requested: bool,
    /// 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<()>,
    /// A predicate to be called on the path determining whether the feature is enabled.
    /// The first name is the name of the test group, the second the path to the test
    /// source.
    enabling_condition: fn(&str, &str) -> bool,
}

/// 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.
    #[allow(dead_code)]
    Explicit,
    /// Every test will be included unless it has the comment `// exclude_for: <feature>`.
    Implicit,
}

fn get_features() -> &'static [Feature] {
    static TESTED_FEATURES: OnceCell<Vec<Feature>> = OnceCell::new();
    TESTED_FEATURES.get_or_init(|| {
        vec![
            // Tests the default configuration.
            Feature {
                name: "default",
                flags: &[],
                inclusion_mode: InclusionMode::Implicit,
                enable_in_ci: true,
                only_if_requested: false,
                separate_baseline: false,
                runner: |p| test_runner_for_feature(p, get_feature_by_name("default")),
                enabling_condition: |_, _| true,
            },
            // Tests with spec simplification pipeline enabled
            Feature {
                name: "simplify",
                flags: &[
                    "--ignore-pragma-opaque-internal-only",
                    "--simplify",
                    "inline",
                ],
                inclusion_mode: InclusionMode::Implicit,
                enable_in_ci: true,
                only_if_requested: false,
                separate_baseline: false,
                runner: |p| test_runner_for_feature(p, get_feature_by_name("simplify")),
                enabling_condition: |_, _| true,
            },
            // Tests with cvc4 as a backend for boogie.
            Feature {
                name: "cvc4",
                flags: &["--use-cvc4"],
                inclusion_mode: InclusionMode::Implicit,
                enable_in_ci: false, // Do not enable in CI until we have more data about stability
                only_if_requested: false,
                separate_baseline: false,
                runner: |p| test_runner_for_feature(p, get_feature_by_name("cvc4")),
                enabling_condition: |group, _| group == "unit",
            },
        ]
    })
}

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

/// 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 {
        diags += &String::from_utf8_lossy(&error_writer.into_inner()).to_string();
        if let Some(ref path) = baseline_path {
            verify_or_update_baseline(path.as_path(), &diags)?
        } else if !diags.is_empty() {
            return Err(anyhow!("Unexpected prover output (expected none): {}", diags).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 dep_flags = vec![
        // stdlib is commonly required
        "--dependency=../move-stdlib/sources",
    ];

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

    // Add inconsistency checking flags
    if read_bool_env_var(ENV_TEST_INCONSISTENCY) {
        flags.push("--check-inconsistency".to_string());
    }

    // Add flag assigning an address to the stdlib.
    flags.push("--named-addresses=Std=0x1".to_string());

    // 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 entry in WalkDir::new(p.clone())
        .follow_links(false)
        .min_depth(1)
        .into_iter()
        .flatten()
    {
        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();
        }
        let root_str = p.to_string_lossy().to_string();
        let path_str = path.to_string_lossy().to_string();
        if included {
            included = (feature.enabling_condition)(group, &path_str);
        }
        if included {
            reqs.push(Requirements::new(
                feature.runner,
                format!("prover {}[{}]", group, feature.name),
                root_str,
                path_str,
            ));
        }
    }
}

// Test entry point based on datatest runner.
fn main() {
    let mut reqs = vec![];
    for feature in get_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;
        }
        if feature_narrow.is_empty() && feature.only_if_requested {
            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");
        }
    }
    datatest_stable::runner(&reqs);
}
<commit_msg>[move-prover][tests] add inconsistency flag to df and stdlib only<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use std::{
    path::{Path, PathBuf},
    sync::atomic::{AtomicBool, Ordering},
};

use anyhow::anyhow;
use codespan_reporting::term::termcolor::Buffer;
use datatest_stable::Requirements;
use itertools::Itertools;
use log::{info, warn};
use once_cell::sync::OnceCell;
use tempfile::TempDir;
use walkdir::WalkDir;

use move_command_line_common::{env::read_env_var, testing::EXP_EXT};
use move_prover::{cli::Options, run_move_prover};
use move_prover_test_utils::{baseline_test::verify_or_update_baseline, extract_test_directives};

const ENV_FLAGS: &str = "MVP_TEST_FLAGS";
const ENV_TEST_EXTENDED: &str = "MVP_TEST_X";
const ENV_TEST_FEATURE: &str = "MVP_TEST_FEATURE";
const ENV_TEST_ON_CI: &str = "MVP_TEST_ON_CI";

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,
    /// True if the tests should only be run if requested by MVP_TEST_FEATURE
    only_if_requested: bool,
    /// 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<()>,
    /// A predicate to be called on the path determining whether the feature is enabled.
    /// The first name is the name of the test group, the second the path to the test
    /// source.
    enabling_condition: fn(&str, &str) -> bool,
}

/// 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.
    #[allow(dead_code)]
    Explicit,
    /// Every test will be included unless it has the comment `// exclude_for: <feature>`.
    Implicit,
}

fn get_features() -> &'static [Feature] {
    static TESTED_FEATURES: OnceCell<Vec<Feature>> = OnceCell::new();
    TESTED_FEATURES.get_or_init(|| {
        vec![
            // Tests the default configuration.
            Feature {
                name: "default",
                flags: &[],
                inclusion_mode: InclusionMode::Implicit,
                enable_in_ci: true,
                only_if_requested: false,
                separate_baseline: false,
                runner: |p| test_runner_for_feature(p, get_feature_by_name("default")),
                enabling_condition: |_, _| true,
            },
            // Tests with spec simplification pipeline enabled
            Feature {
                name: "simplify",
                flags: &[
                    "--ignore-pragma-opaque-internal-only",
                    "--simplify",
                    "inline",
                ],
                inclusion_mode: InclusionMode::Implicit,
                enable_in_ci: true,
                only_if_requested: false,
                separate_baseline: false,
                runner: |p| test_runner_for_feature(p, get_feature_by_name("simplify")),
                enabling_condition: |_, _| true,
            },
            // Tests with cvc4 as a backend for boogie.
            Feature {
                name: "cvc4",
                flags: &["--use-cvc4"],
                inclusion_mode: InclusionMode::Implicit,
                enable_in_ci: false, // Do not enable in CI until we have more data about stability
                only_if_requested: false,
                separate_baseline: false,
                runner: |p| test_runner_for_feature(p, get_feature_by_name("cvc4")),
                enabling_condition: |group, _| group == "unit",
            },
        ]
    })
}

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

/// 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 {
        diags += &String::from_utf8_lossy(&error_writer.into_inner()).to_string();
        if let Some(ref path) = baseline_path {
            verify_or_update_baseline(path.as_path(), &diags)?
        } else if !diags.is_empty() {
            return Err(anyhow!("Unexpected prover output (expected none): {}", diags).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 dep_flags = vec![
        // stdlib is commonly required
        "--dependency=../move-stdlib/sources",
    ];

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

    // Add flag assigning an address to the stdlib.
    flags.push("--named-addresses=Std=0x1".to_string());

    // 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 entry in WalkDir::new(p.clone())
        .follow_links(false)
        .min_depth(1)
        .into_iter()
        .flatten()
    {
        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();
        }
        let root_str = p.to_string_lossy().to_string();
        let path_str = path.to_string_lossy().to_string();
        if included {
            included = (feature.enabling_condition)(group, &path_str);
        }
        if included {
            reqs.push(Requirements::new(
                feature.runner,
                format!("prover {}[{}]", group, feature.name),
                root_str,
                path_str,
            ));
        }
    }
}

// Test entry point based on datatest runner.
fn main() {
    let mut reqs = vec![];
    for feature in get_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;
        }
        if feature_narrow.is_empty() && feature.only_if_requested {
            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");
        }
    }
    datatest_stable::runner(&reqs);
}
<|endoftext|>


<commit_before>extern crate ctest;

use std::env;

fn main() {
    let mut cfg = ctest::TestGenerator::new();

    if let Ok(out) = env::var("DEP_CURL_INCLUDE") {
        cfg.include(&out);
    }

    if env::var("TARGET").unwrap().contains("msvc") {
        cfg.flag("/wd4574"); // did you mean to use '#if INCL_WINSOCK_API_TYPEDEFS'
    }

    cfg.header("curl/curl.h");
    cfg.define("CURL_STATICLIB", None);
    cfg.field_name(|s, field| {
        if s == "curl_fileinfo" {
            field.replace("strings_", "strings.")
        } else if s == "CURLMsg" && field == "data" {
            "data.whatever".to_string()
        } else {
            field.to_string()
        }
    });
    cfg.type_name(|s, is_struct| {
        match s {
            "CURL" |
            "CURLM" |
            "CURLSH" |
            "curl_version_info_data" => s.to_string(),
            "curl_khtype" |
            "curl_khstat" |
            "curl_khmatch" => format!("enum {}", s),
            s if is_struct => format!("struct {}", s),
            "sockaddr" => format!("struct sockaddr"),
            s => s.to_string(),
        }
    });
    // cfg.fn_cname(|s, l| l.unwrap_or(s).to_string());
    cfg.skip_type(|n| n == "__enum_ty");
    cfg.skip_signededness(|s| {
        s.ends_with("callback") || s.ends_with("function")
    });

    cfg.skip_const(|s| {
        // Ubuntu Xenial 16.04 ships with version 7.47.0 of curl, so explicitly
        // skip constants introduced after that.
        // CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE was introduced in 7.49.0
        s == "CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE" ||

        // OSX doesn't have this yet
        s == "CURLSSLOPT_NO_REVOKE" ||

        // Disable HTTP/2 checking if feature not enabled
        (!cfg!(feature = "http2") && s.starts_with("CURL_HTTP_VERSION_2")) ||

        // A lot of curl versions doesn't support unix sockets
        s == "CURLOPT_UNIX_SOCKET_PATH" || s == "CURL_VERSION_UNIX_SOCKETS"
    });

    if cfg!(target_env = "msvc") {
        cfg.skip_fn_ptrcheck(|s| s.starts_with("curl_"));
    }

    cfg.generate("../curl-sys/lib.rs", "all.rs");
}
<commit_msg>Fix systest whitelist<commit_after>extern crate ctest;

use std::env;

fn main() {
    let mut cfg = ctest::TestGenerator::new();

    if let Ok(out) = env::var("DEP_CURL_INCLUDE") {
        cfg.include(&out);
    }

    if env::var("TARGET").unwrap().contains("msvc") {
        cfg.flag("/wd4574"); // did you mean to use '#if INCL_WINSOCK_API_TYPEDEFS'
    }

    cfg.header("curl/curl.h");
    cfg.define("CURL_STATICLIB", None);
    cfg.field_name(|s, field| {
        if s == "curl_fileinfo" {
            field.replace("strings_", "strings.")
        } else if s == "CURLMsg" && field == "data" {
            "data.whatever".to_string()
        } else {
            field.to_string()
        }
    });
    cfg.type_name(|s, is_struct| {
        match s {
            "CURL" |
            "CURLM" |
            "CURLSH" |
            "curl_version_info_data" => s.to_string(),
            "curl_khtype" |
            "curl_khstat" |
            "curl_khmatch" => format!("enum {}", s),
            s if is_struct => format!("struct {}", s),
            "sockaddr" => format!("struct sockaddr"),
            s => s.to_string(),
        }
    });
    // cfg.fn_cname(|s, l| l.unwrap_or(s).to_string());
    cfg.skip_type(|n| n == "__enum_ty");
    cfg.skip_signededness(|s| {
        s.ends_with("callback") || s.ends_with("function")
    });

    cfg.skip_const(|s| {
        // Ubuntu 14.04 (Trusty) which we test on ships with version 7.35.0 of
        // curl, so explicitly skip constants introduced after that.
        // CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE was introduced in 7.49.0
        s == "CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE" ||

        // OSX doesn't have this yet
        s == "CURLSSLOPT_NO_REVOKE" ||

        // CURLPIPE helpers were added in 7.43.0
        s.starts_with("CURLPIPE_") ||

        // Disable HTTP/2 checking if feature not enabled
        (!cfg!(feature = "http2") && s.starts_with("CURL_HTTP_VERSION_2")) ||

        // A lot of curl versions doesn't support unix sockets
        s == "CURLOPT_UNIX_SOCKET_PATH" || s == "CURL_VERSION_UNIX_SOCKETS"
    });

    if cfg!(target_env = "msvc") {
        cfg.skip_fn_ptrcheck(|s| s.starts_with("curl_"));
    }

    cfg.generate("../curl-sys/lib.rs", "all.rs");
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
extern crate cgmath;

use glium::{DisplayBuild, Surface};
use glium::glutin;
use cgmath::{EuclideanVector, Vector, Point};

#[derive(Copy, Clone)]
struct Vertex {
    position: (f32, f32, f32),
    color: (f32, f32, f32),
}
implement_vertex!(Vertex, position, color);

#[derive(Copy, Clone)]
struct DrawId {
    draw_id: u32,
}
implement_vertex!(DrawId, draw_id);

struct Transform {
    transforms: [[[f32; 4]; 4]],
}
implement_buffer_content!(Transform);
implement_uniform_block!(Transform, transforms);

const OBJECTS_X: usize = 64;
const OBJECTS_Y: usize = 64;
const OBJECTS_Z: usize = 64;
const OBJECTS_COUNT: usize = OBJECTS_X * OBJECTS_Y * OBJECTS_Z;

fn main() {
    let display = glutin::WindowBuilder::new()
                    .build_glium()
                    .unwrap();

    let vertex_buffer = glium::VertexBuffer::new(&display, &[
        Vertex { position: (-0.5,  0.5, -0.5), color: (0.0,  1.0,  0.0) },
        Vertex { position: ( 0.5,  0.5, -0.5), color: (1.0,  1.0,  0.0) },
        Vertex { position: ( 0.5,  0.5,  0.5), color: (1.0,  1.0,  1.0) },
        Vertex { position: (-0.5,  0.5,  0.5), color: (0.0,  1.0,  1.0) },
        Vertex { position: (-0.5, -0.5,  0.5), color: (0.0,  0.0,  1.0) },
        Vertex { position: ( 0.5, -0.5,  0.5), color: (1.0,  0.0,  1.0) },
        Vertex { position: ( 0.5, -0.5, -0.5), color: (1.0,  0.0,  0.0) },
        Vertex { position: (-0.5, -0.5, -0.5), color: (0.0,  0.0,  0.0) },
    ]);

    let drawids_buffer = glium::VertexBuffer::new(&display,
        (0 .. OBJECTS_COUNT).map(|c| DrawId { draw_id: c as u32 }).collect::<Vec<_>>()
    );

    let index_buffer = glium::index::IndexBuffer::new(&display,
        glium::index::PrimitiveType::TrianglesList,
        &[
            0, 1, 2, 0, 2, 3,
            4, 5, 6, 4, 6, 7,
            3, 2, 5, 3, 5, 4,
            2, 1, 6, 2, 6, 5,
            1, 7, 6, 1, 0, 7,
            0, 3, 4, 0, 4, 7u16
        ][..]
    );

    let program = program!(&display,
        410 => {
            vertex: include_str!("../cubes_gl_buffer_storage_vs.glsl"),
            fragment: include_str!("../cubes_gl_buffer_storage_fs.glsl"),
        }
    ).unwrap();

    let mut commands = glium::index::DrawCommandsIndicesBuffer::
                                  empty_dynamic_if_supported(&display, OBJECTS_COUNT * 3).unwrap();
    let mut transform_buffer = glium::uniforms::UniformBuffer::<Transform>::empty_unsized_if_supported(&display,
                                                                  16 * 4 * OBJECTS_COUNT).unwrap();

    let mut iteration = 0;
    let mut buf_num = 0;

    loop {
        // writing the commands
        {
            let commands = commands.slice_mut(buf_num * OBJECTS_COUNT .. (buf_num + 1) * OBJECTS_COUNT).unwrap();
            let len = commands.len();
            let mut commands = commands.map_write();
            for i in 0 .. len {
                commands.set(i, glium::index::DrawCommandIndices {
                    count: index_buffer.len() as u32,
                    instance_count: 1,
                    first_index: 0,
                    base_vertex: 0,
                    base_instance: i as u32,
                });
            }
        }

        // writing the transforms
        {
            let angle = iteration as f32 * 0.01;
            iteration += 1;
            if angle > 2.0 * 3.141592 {
                iteration = 0;
            }

            let mut transforms = transform_buffer.map();
            let mut index = 0;

            for x in (0 .. OBJECTS_X) {
                for y in (0 .. OBJECTS_Y) {
                    for z in (0 .. OBJECTS_Z) {
                        let s = angle.sin();
                        let c = angle.cos();

                        let mut mat = [
                            [c,  -s,   0.0, 0.0],
                            [s,   c,   0.0, 0.0],
                            [0.0, 0.0, 1.0, 0.0],
                            [0.0, 0.0, 0.0, 1.0],
                        ];

                        mat[0][0] = 2.0 * (x as isize - OBJECTS_X as isize) as f32;
                        mat[3][1] = 2.0 * (y as isize - OBJECTS_Y as isize) as f32;
                        mat[3][2] = 2.0 * (z as isize - OBJECTS_Z as isize) as f32;

                        transforms.transforms[index] = mat;
                        index += 1;
                    }
                }
            }
        }

        let commands = commands.slice_mut(buf_num * OBJECTS_COUNT .. (buf_num + 1) * OBJECTS_COUNT).unwrap();
        let indices = glium::index::IndicesSource::MultidrawElement {
            commands: commands.as_slice_any(),
            indices: index_buffer.as_slice_any(),
            data_type: index_buffer.get_indices_type(),
            primitives: index_buffer.get_primitives_type(),
        };

        let persp = cgmath::perspective(cgmath::deg(45.0), 1.0, 0.1, 10000.0);
        let dir = cgmath::Vector3::new(-0.5, -1.0, 1.0).normalize();
        let at = dir.mul_s(-250.0);
        let view = cgmath::Matrix4::look_at(&cgmath::Point3::from_vec(&at),
                                            &cgmath::Point3::from_vec(&dir),
                                            &cgmath::Vector3::new(0.0, 0.0, 1.0));
        let matrix = persp * view;

        let params = glium::DrawParameters {
            backface_culling: glium::draw_parameters::BackfaceCullingMode::CullCounterClockWise,
            depth_test: glium::draw_parameters::DepthTest::IfLess,
            depth_write: true,
            .. Default::default()
        };

        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.1, 0.0, 1.0), 1.0);
        target.draw((&vertex_buffer, drawids_buffer.per_instance_if_supported().unwrap()),
                    indices, &program, &uniform! { CB0: &transform_buffer, ViewProjection: matrix },
                    &params).unwrap();
        target.finish().unwrap();

        buf_num += 1;
        if buf_num >= 3 { buf_num = 0; }

        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<commit_msg>Fix aspect ratio<commit_after>#[macro_use]
extern crate glium;
extern crate cgmath;

use glium::{DisplayBuild, Surface};
use glium::glutin;
use cgmath::{EuclideanVector, Vector, Point};

#[derive(Copy, Clone)]
struct Vertex {
    position: (f32, f32, f32),
    color: (f32, f32, f32),
}
implement_vertex!(Vertex, position, color);

#[derive(Copy, Clone)]
struct DrawId {
    draw_id: u32,
}
implement_vertex!(DrawId, draw_id);

struct Transform {
    transforms: [[[f32; 4]; 4]],
}
implement_buffer_content!(Transform);
implement_uniform_block!(Transform, transforms);

const OBJECTS_X: usize = 64;
const OBJECTS_Y: usize = 64;
const OBJECTS_Z: usize = 64;
const OBJECTS_COUNT: usize = OBJECTS_X * OBJECTS_Y * OBJECTS_Z;

fn main() {
    let display = glutin::WindowBuilder::new()
                    .build_glium()
                    .unwrap();

    let vertex_buffer = glium::VertexBuffer::new(&display, &[
        Vertex { position: (-0.5,  0.5, -0.5), color: (0.0,  1.0,  0.0) },
        Vertex { position: ( 0.5,  0.5, -0.5), color: (1.0,  1.0,  0.0) },
        Vertex { position: ( 0.5,  0.5,  0.5), color: (1.0,  1.0,  1.0) },
        Vertex { position: (-0.5,  0.5,  0.5), color: (0.0,  1.0,  1.0) },
        Vertex { position: (-0.5, -0.5,  0.5), color: (0.0,  0.0,  1.0) },
        Vertex { position: ( 0.5, -0.5,  0.5), color: (1.0,  0.0,  1.0) },
        Vertex { position: ( 0.5, -0.5, -0.5), color: (1.0,  0.0,  0.0) },
        Vertex { position: (-0.5, -0.5, -0.5), color: (0.0,  0.0,  0.0) },
    ]);

    let drawids_buffer = glium::VertexBuffer::new(&display,
        (0 .. OBJECTS_COUNT).map(|c| DrawId { draw_id: c as u32 }).collect::<Vec<_>>()
    );

    let index_buffer = glium::index::IndexBuffer::new(&display,
        glium::index::PrimitiveType::TrianglesList,
        &[
            0, 1, 2, 0, 2, 3,
            4, 5, 6, 4, 6, 7,
            3, 2, 5, 3, 5, 4,
            2, 1, 6, 2, 6, 5,
            1, 7, 6, 1, 0, 7,
            0, 3, 4, 0, 4, 7u16
        ][..]
    );

    let program = program!(&display,
        410 => {
            vertex: include_str!("../cubes_gl_buffer_storage_vs.glsl"),
            fragment: include_str!("../cubes_gl_buffer_storage_fs.glsl"),
        }
    ).unwrap();

    let mut commands = glium::index::DrawCommandsIndicesBuffer::
                                  empty_dynamic_if_supported(&display, OBJECTS_COUNT * 3).unwrap();
    let mut transform_buffer = glium::uniforms::UniformBuffer::<Transform>::empty_unsized_if_supported(&display,
                                                                  16 * 4 * OBJECTS_COUNT).unwrap();

    let mut iteration = 0;
    let mut buf_num = 0;

    loop {
        // writing the commands
        {
            let commands = commands.slice_mut(buf_num * OBJECTS_COUNT .. (buf_num + 1) * OBJECTS_COUNT).unwrap();
            let len = commands.len();
            let mut commands = commands.map_write();
            for i in 0 .. len {
                commands.set(i, glium::index::DrawCommandIndices {
                    count: index_buffer.len() as u32,
                    instance_count: 1,
                    first_index: 0,
                    base_vertex: 0,
                    base_instance: i as u32,
                });
            }
        }

        // writing the transforms
        {
            let angle = iteration as f32 * 0.01;
            iteration += 1;
            if angle > 2.0 * 3.141592 {
                iteration = 0;
            }

            let mut transforms = transform_buffer.map();
            let mut index = 0;

            for x in (0 .. OBJECTS_X) {
                for y in (0 .. OBJECTS_Y) {
                    for z in (0 .. OBJECTS_Z) {
                        let s = angle.sin();
                        let c = angle.cos();

                        let mut mat = [
                            [c,  -s,   0.0, 0.0],
                            [s,   c,   0.0, 0.0],
                            [0.0, 0.0, 1.0, 0.0],
                            [0.0, 0.0, 0.0, 1.0],
                        ];

                        mat[0][0] = 2.0 * (x as isize - OBJECTS_X as isize) as f32;
                        mat[3][1] = 2.0 * (y as isize - OBJECTS_Y as isize) as f32;
                        mat[3][2] = 2.0 * (z as isize - OBJECTS_Z as isize) as f32;

                        transforms.transforms[index] = mat;
                        index += 1;
                    }
                }
            }
        }

        let commands = commands.slice_mut(buf_num * OBJECTS_COUNT .. (buf_num + 1) * OBJECTS_COUNT).unwrap();
        let indices = glium::index::IndicesSource::MultidrawElement {
            commands: commands.as_slice_any(),
            indices: index_buffer.as_slice_any(),
            data_type: index_buffer.get_indices_type(),
            primitives: index_buffer.get_primitives_type(),
        };

        let (w, h) = display.get_framebuffer_dimensions();
        let persp = cgmath::perspective(cgmath::deg(45.0), w as f32 / h as f32, 0.1, 10000.0);
        let dir = cgmath::Vector3::new(-0.5, -1.0, 1.0).normalize();
        let at = dir.mul_s(-250.0);
        let view = cgmath::Matrix4::look_at(&cgmath::Point3::from_vec(&at),
                                            &cgmath::Point3::from_vec(&dir),
                                            &cgmath::Vector3::new(0.0, 0.0, 1.0));
        let matrix = persp * view;

        let params = glium::DrawParameters {
            backface_culling: glium::draw_parameters::BackfaceCullingMode::CullCounterClockWise,
            depth_test: glium::draw_parameters::DepthTest::IfLess,
            depth_write: true,
            .. Default::default()
        };

        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.1, 0.0, 1.0), 1.0);
        target.draw((&vertex_buffer, drawids_buffer.per_instance_if_supported().unwrap()),
                    indices, &program, &uniform! { CB0: &transform_buffer, ViewProjection: matrix },
                    &params).unwrap();
        target.finish().unwrap();

        buf_num += 1;
        if buf_num >= 3 { buf_num = 0; }

        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return,
                _ => ()
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::HashSet;

use serde_json;
use failure::Context;

use errors::prelude::*;
use services::ledger::merkletree::merkletree::MerkleTree;
use services::pool::merkle_tree_factory;
use services::pool::rust_base58::{FromBase58, ToBase58};
use services::pool::types::{CatchupReq, Message};

pub enum CatchupProgress {
    ShouldBeStarted(
        Vec<u8>, //target_mt_root
        usize, //target_mt_size
        MerkleTree,
    ),
    NotNeeded(MerkleTree),
    Restart(MerkleTree),
    InProgress,
}

pub fn build_catchup_req(merkle: &MerkleTree, target_mt_size: usize) -> IndyResult<Option<(String, String)>> {
    let txns_cnt = target_mt_size - merkle.count();

    if txns_cnt <= 0 {
        warn!("No transactions to catch up!");
        return Ok(None);
    }
    let seq_no_start = merkle.count() + 1;
    let seq_no_end = target_mt_size;

    let cr = CatchupReq {
        ledgerId: 0,
        seqNoStart: seq_no_start.clone(),
        seqNoEnd: seq_no_end.clone(),
        catchupTill: target_mt_size,
    };

    let req_id = format!("{}{}", seq_no_start, seq_no_end);

    let req_json = serde_json::to_string(&Message::CatchupReq(cr))
        .to_indy(IndyErrorKind::InvalidState, "Cannot serialize CatchupRequest")?;

    trace!("catchup_req msg: {:?}", req_json);
    Ok(Some((req_id, req_json)))
}

pub fn check_nodes_responses_on_status(nodes_votes: &HashMap<(String, usize, Option<Vec<String>>), HashSet<String>>,
                                       merkle_tree: &MerkleTree,
                                       node_cnt: usize,
                                       f: usize,
                                       pool_name: &str) -> IndyResult<CatchupProgress> {
    let (votes, timeout_votes): (HashMap<&(String, usize, Option<Vec<String>>), usize>, HashMap<&(String, usize, Option<Vec<String>>), usize>) =
        nodes_votes
            .iter()
            .map(|(key, val)| (key, val.len()))
            .partition(|((key, _, _), _)| key != "timeout");

    let most_popular_not_timeout =
        votes
            .iter()
            .max_by_key(|entry| entry.1);

    let timeout_votes = timeout_votes.iter().last();

    if let Some((most_popular_not_timeout_vote, votes_cnt)) = most_popular_not_timeout {
        if *votes_cnt == f + 1 {
            return _try_to_catch_up(most_popular_not_timeout_vote, merkle_tree).or_else(|err| {
                if merkle_tree_factory::drop_cache(pool_name).is_ok() {
                    let merkle_tree = merkle_tree_factory::create(pool_name)?;
                    _try_to_catch_up(most_popular_not_timeout_vote, &merkle_tree)
                } else {
                    Err(err)
                }
            });
        } else {
            return _if_consensus_reachable(nodes_votes, node_cnt, *votes_cnt, f, pool_name);
        }
    } else if let Some((_, votes_cnt)) = timeout_votes {
        if *votes_cnt == node_cnt - f {
            return _try_to_restart_catch_up(pool_name, err_msg(IndyErrorKind::PoolTimeout, "Pool timeout"));
        } else {
            return _if_consensus_reachable(nodes_votes, node_cnt, *votes_cnt, f, pool_name);
        }
    }
    Ok(CatchupProgress::InProgress)
}

fn _if_consensus_reachable(nodes_votes: &HashMap<(String, usize, Option<Vec<String>>), HashSet<String>>,
                           node_cnt: usize,
                           votes_cnt: usize,
                           f: usize,
                           pool_name: &str) -> IndyResult<CatchupProgress> {
    let reps_cnt: usize = nodes_votes.values().map(HashSet::len).sum();
    let positive_votes_cnt = votes_cnt + (node_cnt - reps_cnt);
    let is_consensus_not_reachable = positive_votes_cnt < node_cnt - f;
    if is_consensus_not_reachable {
        //TODO: maybe we should change the error, but it was made to escape changing of ErrorCode returned to client
        _try_to_restart_catch_up(pool_name, err_msg(IndyErrorKind::PoolTimeout, "No consensus possible"))
    } else {
        Ok(CatchupProgress::InProgress)
    }
}

fn _try_to_restart_catch_up(pool_name: &str, err: IndyError) -> IndyResult<CatchupProgress> {
    if merkle_tree_factory::drop_cache(pool_name).is_ok() {
        let merkle_tree = merkle_tree_factory::create(pool_name)?;
        Ok(CatchupProgress::Restart(merkle_tree))
    } else {
        Err(err)
    }
}

fn _try_to_catch_up(ledger_status: &(String, usize, Option<Vec<String>>), merkle_tree: &MerkleTree) -> IndyResult<CatchupProgress> {
    let &(ref target_mt_root, target_mt_size, ref hashes) = ledger_status;
    let cur_mt_size = merkle_tree.count();
    let cur_mt_hash = merkle_tree.root_hash().to_base58();

    if target_mt_size == cur_mt_size {
        if cur_mt_hash.eq(target_mt_root) {
            Ok(CatchupProgress::NotNeeded(merkle_tree.clone()))
        } else {
            Err(err_msg(IndyErrorKind::InvalidState,
                               "Ledger merkle tree is not acceptable for current tree."))
        }
    } else if target_mt_size > cur_mt_size {
        let target_mt_root = target_mt_root
            .from_base58()
            .map_err(|err| Context::new(err))
            .to_indy(IndyErrorKind::InvalidStructure, "Can't parse target MerkleTree hash from nodes responses")?; // FIXME: review kind

        match *hashes {
            None => (),
            Some(ref hashes) => check_cons_proofs(merkle_tree, hashes, &target_mt_root, target_mt_size)?,
        };

        Ok(CatchupProgress::ShouldBeStarted(target_mt_root, target_mt_size, merkle_tree.clone()))
    } else {
        Err(err_msg(IndyErrorKind::InvalidState, "Local merkle tree greater than mt from ledger"))
    }
}

pub fn check_cons_proofs(mt: &MerkleTree, cons_proofs: &Vec<String>, target_mt_root: &Vec<u8>, target_mt_size: usize) -> IndyResult<()> {
    let mut bytes_proofs: Vec<Vec<u8>> = Vec::new();

    for cons_proof in cons_proofs {
        let cons_proof: &String = cons_proof;

        bytes_proofs.push(
            cons_proof
                .from_base58()
                .map_err(|err| Context::new(err))
                .to_indy(IndyErrorKind::InvalidStructure, "Can't decode node consistency proof")? // FIXME: review kind
        );
    }

    if !mt.consistency_proof(target_mt_root, target_mt_size, &bytes_proofs)? {
        return Err(err_msg(IndyErrorKind::InvalidState, "Consistency proof verification failed")); // FIXME: review kind
    }

    Ok(())
}<commit_msg>Fix bad comparison IS-825<commit_after>use std::collections::HashMap;
use std::collections::HashSet;

use serde_json;
use failure::Context;

use errors::prelude::*;
use services::ledger::merkletree::merkletree::MerkleTree;
use services::pool::merkle_tree_factory;
use services::pool::rust_base58::{FromBase58, ToBase58};
use services::pool::types::{CatchupReq, Message};

pub enum CatchupProgress {
    ShouldBeStarted(
        Vec<u8>, //target_mt_root
        usize, //target_mt_size
        MerkleTree,
    ),
    NotNeeded(MerkleTree),
    Restart(MerkleTree),
    InProgress,
}

pub fn build_catchup_req(merkle: &MerkleTree, target_mt_size: usize) -> IndyResult<Option<(String, String)>> {
    if merkle.count() >= target_mt_size  {
        warn!("No transactions to catch up!");
        return Ok(None);
    }
    let seq_no_start = merkle.count() + 1;
    let seq_no_end = target_mt_size;

    let cr = CatchupReq {
        ledgerId: 0,
        seqNoStart: seq_no_start.clone(),
        seqNoEnd: seq_no_end.clone(),
        catchupTill: target_mt_size,
    };

    let req_id = format!("{}{}", seq_no_start, seq_no_end);

    let req_json = serde_json::to_string(&Message::CatchupReq(cr))
        .to_indy(IndyErrorKind::InvalidState, "Cannot serialize CatchupRequest")?;

    trace!("catchup_req msg: {:?}", req_json);
    Ok(Some((req_id, req_json)))
}

pub fn check_nodes_responses_on_status(nodes_votes: &HashMap<(String, usize, Option<Vec<String>>), HashSet<String>>,
                                       merkle_tree: &MerkleTree,
                                       node_cnt: usize,
                                       f: usize,
                                       pool_name: &str) -> IndyResult<CatchupProgress> {
    let (votes, timeout_votes): (HashMap<&(String, usize, Option<Vec<String>>), usize>, HashMap<&(String, usize, Option<Vec<String>>), usize>) =
        nodes_votes
            .iter()
            .map(|(key, val)| (key, val.len()))
            .partition(|((key, _, _), _)| key != "timeout");

    let most_popular_not_timeout =
        votes
            .iter()
            .max_by_key(|entry| entry.1);

    let timeout_votes = timeout_votes.iter().last();

    if let Some((most_popular_not_timeout_vote, votes_cnt)) = most_popular_not_timeout {
        if *votes_cnt == f + 1 {
            return _try_to_catch_up(most_popular_not_timeout_vote, merkle_tree).or_else(|err| {
                if merkle_tree_factory::drop_cache(pool_name).is_ok() {
                    let merkle_tree = merkle_tree_factory::create(pool_name)?;
                    _try_to_catch_up(most_popular_not_timeout_vote, &merkle_tree)
                } else {
                    Err(err)
                }
            });
        } else {
            return _if_consensus_reachable(nodes_votes, node_cnt, *votes_cnt, f, pool_name);
        }
    } else if let Some((_, votes_cnt)) = timeout_votes {
        if *votes_cnt == node_cnt - f {
            return _try_to_restart_catch_up(pool_name, err_msg(IndyErrorKind::PoolTimeout, "Pool timeout"));
        } else {
            return _if_consensus_reachable(nodes_votes, node_cnt, *votes_cnt, f, pool_name);
        }
    }
    Ok(CatchupProgress::InProgress)
}

fn _if_consensus_reachable(nodes_votes: &HashMap<(String, usize, Option<Vec<String>>), HashSet<String>>,
                           node_cnt: usize,
                           votes_cnt: usize,
                           f: usize,
                           pool_name: &str) -> IndyResult<CatchupProgress> {
    let reps_cnt: usize = nodes_votes.values().map(HashSet::len).sum();
    let positive_votes_cnt = votes_cnt + (node_cnt - reps_cnt);
    let is_consensus_not_reachable = positive_votes_cnt < node_cnt - f;
    if is_consensus_not_reachable {
        //TODO: maybe we should change the error, but it was made to escape changing of ErrorCode returned to client
        _try_to_restart_catch_up(pool_name, err_msg(IndyErrorKind::PoolTimeout, "No consensus possible"))
    } else {
        Ok(CatchupProgress::InProgress)
    }
}

fn _try_to_restart_catch_up(pool_name: &str, err: IndyError) -> IndyResult<CatchupProgress> {
    if merkle_tree_factory::drop_cache(pool_name).is_ok() {
        let merkle_tree = merkle_tree_factory::create(pool_name)?;
        Ok(CatchupProgress::Restart(merkle_tree))
    } else {
        Err(err)
    }
}

fn _try_to_catch_up(ledger_status: &(String, usize, Option<Vec<String>>), merkle_tree: &MerkleTree) -> IndyResult<CatchupProgress> {
    let &(ref target_mt_root, target_mt_size, ref hashes) = ledger_status;
    let cur_mt_size = merkle_tree.count();
    let cur_mt_hash = merkle_tree.root_hash().to_base58();

    if target_mt_size == cur_mt_size {
        if cur_mt_hash.eq(target_mt_root) {
            Ok(CatchupProgress::NotNeeded(merkle_tree.clone()))
        } else {
            Err(err_msg(IndyErrorKind::InvalidState,
                               "Ledger merkle tree is not acceptable for current tree."))
        }
    } else if target_mt_size > cur_mt_size {
        let target_mt_root = target_mt_root
            .from_base58()
            .map_err(|err| Context::new(err))
            .to_indy(IndyErrorKind::InvalidStructure, "Can't parse target MerkleTree hash from nodes responses")?; // FIXME: review kind

        match *hashes {
            None => (),
            Some(ref hashes) => check_cons_proofs(merkle_tree, hashes, &target_mt_root, target_mt_size)?,
        };

        Ok(CatchupProgress::ShouldBeStarted(target_mt_root, target_mt_size, merkle_tree.clone()))
    } else {
        Err(err_msg(IndyErrorKind::InvalidState, "Local merkle tree greater than mt from ledger"))
    }
}

pub fn check_cons_proofs(mt: &MerkleTree, cons_proofs: &Vec<String>, target_mt_root: &Vec<u8>, target_mt_size: usize) -> IndyResult<()> {
    let mut bytes_proofs: Vec<Vec<u8>> = Vec::new();

    for cons_proof in cons_proofs {
        let cons_proof: &String = cons_proof;

        bytes_proofs.push(
            cons_proof
                .from_base58()
                .map_err(|err| Context::new(err))
                .to_indy(IndyErrorKind::InvalidStructure, "Can't decode node consistency proof")? // FIXME: review kind
        );
    }

    if !mt.consistency_proof(target_mt_root, target_mt_size, &bytes_proofs)? {
        return Err(err_msg(IndyErrorKind::InvalidState, "Consistency proof verification failed")); // FIXME: review kind
    }

    Ok(())
}<|endoftext|>


<commit_before>
extern crate arrayvec;
#[macro_use] extern crate bencher;

use arrayvec::ArrayVec;

use bencher::Bencher;
use bencher::black_box;

fn extend_with_constant(b: &mut Bencher) {
    let mut v = ArrayVec::<[u8; 512]>::new();
    let cap = v.capacity();
    b.iter(|| {
        v.clear();
        v.extend((0..cap).map(|_| 1));
        v[0]
    });
    b.bytes = v.capacity() as u64;
}

fn extend_with_range(b: &mut Bencher) {
    let mut v = ArrayVec::<[u8; 512]>::new();
    let cap = v.capacity();
    b.iter(|| {
        v.clear();
        v.extend((0..cap).map(|x| x as _));
        v[0]
    });
    b.bytes = v.capacity() as u64;
}

fn extend_with_slice(b: &mut Bencher) {
    let mut v = ArrayVec::<[u8; 512]>::new();
    let data = [1; 512];
    b.iter(|| {
        v.clear();
        v.extend(black_box(data.iter()).cloned());
        v[0]
    });
    b.bytes = v.capacity() as u64;
}

benchmark_group!(benches, extend_with_constant, extend_with_range, extend_with_slice);
benchmark_main!(benches);
<commit_msg>TEST: add benchmark for extend_from_slice<commit_after>
extern crate arrayvec;
#[macro_use] extern crate bencher;

use arrayvec::ArrayVec;

use bencher::Bencher;
use bencher::black_box;

fn extend_with_constant(b: &mut Bencher) {
    let mut v = ArrayVec::<[u8; 512]>::new();
    let cap = v.capacity();
    b.iter(|| {
        v.clear();
        v.extend((0..cap).map(|_| 1));
        v[0]
    });
    b.bytes = v.capacity() as u64;
}

fn extend_with_range(b: &mut Bencher) {
    let mut v = ArrayVec::<[u8; 512]>::new();
    let cap = v.capacity();
    b.iter(|| {
        v.clear();
        v.extend((0..cap).map(|x| x as _));
        v[0]
    });
    b.bytes = v.capacity() as u64;
}

fn extend_with_slice(b: &mut Bencher) {
    let mut v = ArrayVec::<[u8; 512]>::new();
    let data = [1; 512];
    b.iter(|| {
        v.clear();
        v.extend(black_box(data.iter()).cloned());
        v[0]
    });
    b.bytes = v.capacity() as u64;
}

fn extend_with_slice_fn(b: &mut Bencher) {
    let mut v = ArrayVec::<[u8; 512]>::new();
    let data = [1; 512];
    b.iter(|| {
        v.clear();
        black_box(v.extend_from_slice(&data));
        v[0]
    });
    b.bytes = v.capacity() as u64;
}

benchmark_group!(benches, extend_with_constant, extend_with_range, extend_with_slice, extend_with_slice_fn);
benchmark_main!(benches);
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

//! tarpc is an RPC framework for rust with a focus on ease of use. Defining a
//! service can be done in just a few lines of code, and most of the boilerplate of
//! writing a server is taken care of for you.
//!
//! ## What is an RPC framework?
//! "RPC" stands for "Remote Procedure Call," a function call where the work of
//! producing the return value is being done somewhere else. When an rpc function is
//! invoked, behind the scenes the function contacts some other process somewhere
//! and asks them to evaluate the function instead. The original function then
//! returns the value produced by the other process.
//!
//! RPC frameworks are a fundamental building block of most microservices-oriented
//! architectures. Two well-known ones are [gRPC](http://www.grpc.io) and
//! [Cap'n Proto](https://capnproto.org/).
//!
//! tarpc differentiates itself from other RPC frameworks by defining the schema in code,
//! rather than in a separate language such as .proto. This means there's no separate compilation
//! process, and no cognitive context switching between different languages. Additionally, it
//! works with the community-backed library serde: any serde-serializable type can be used as
//! arguments to tarpc fns.
//!
//! ## Example
//!
//! Here's a small service.
//!
//! ```rust
//! #![feature(futures_api, pin, arbitrary_self_types, await_macro, async_await, proc_macro_hygiene)]
//!
//!
//! use futures::{
//!     compat::TokioDefaultSpawner,
//!     future::{self, Ready},
//!     prelude::*,
//! };
//! use tarpc::{
//!     client, context,
//!     server::{self, Handler},
//! };
//! use std::io;
//!
//! // This is the service definition. It looks a lot like a trait definition.
//! // It defines one RPC, hello, which takes one arg, name, and returns a String.
//! tarpc::service! {
//!     /// Returns a greeting for name.
//!     rpc hello(name: String) -> String;
//! }
//!
//! // This is the type that implements the generated Service trait. It is the business logic
//! // and is used to start the server.
//! #[derive(Clone)]
//! struct HelloServer;
//!
//! impl Service for HelloServer {
//!     // Each defined rpc generates two items in the trait, a fn that serves the RPC, and
//!     // an associated type representing the future output by the fn.
//!
//!     type HelloFut = Ready<String>;
//!
//!     fn hello(&self, _: context::Context, name: String) -> Self::HelloFut {
//!         future::ready(format!("Hello, {}!", name))
//!     }
//! }
//!
//! async fn run() -> io::Result<()> {
//!     // bincode_transport is provided by the associated crate bincode-transport. It makes it easy
//!     // to start up a serde-powered bincode serialization strategy over TCP.
//!     let transport = bincode_transport::listen(&"0.0.0.0:0".parse().unwrap())?;
//!     let addr = transport.local_addr();
//!
//!     // The server is configured with the defaults.
//!     let server = server::new(server::Config::default())
//!         // Server can listen on any type that implements the Transport trait.
//!         .incoming(transport)
//!         // Close the stream after the client connects
//!         .take(1)
//!         // serve is generated by the service! macro. It takes as input any type implementing
//!         // the generated Service trait.
//!         .respond_with(serve(HelloServer));
//!
//!     tokio_executor::spawn(server.unit_error().boxed().compat());
//!
//!     let transport = await!(bincode_transport::connect(&addr))?;
//!
//!     // new_stub is generated by the service! macro. Like Server, it takes a config and any
//!     // Transport as input, and returns a Client, also generated by the macro.
//!     // by the service mcro.
//!     let mut client = await!(new_stub(client::Config::default(), transport))?;
//!
//!     // The client has an RPC method for each RPC defined in service!. It takes the same args
//!     // as defined, with the addition of a Context, which is always the first arg. The Context
//!     // specifies a deadline and trace information which can be helpful in debugging requests.
//!     let hello = await!(client.hello(context::current(), "Stim".to_string()))?;
//!
//!     println!("{}", hello);
//!
//!     Ok(())
//! }
//!
//! fn main() {
//!     tarpc::init(TokioDefaultSpawner);
//!     tokio::run(run()
//!             .map_err(|e| eprintln!("Oh no: {}", e))
//!             .boxed()
//!             .compat(),
//!     );
//! }
//! ```

#![deny(missing_docs, missing_debug_implementations)]
#![feature(futures_api, pin, await_macro, async_await, decl_macro)]
#![cfg_attr(test, feature(proc_macro_hygiene, arbitrary_self_types))]

#[doc(hidden)]
pub use futures;
pub use rpc::*;
#[cfg(feature = "serde")]
#[doc(hidden)]
pub use serde;
#[doc(hidden)]
pub use tarpc_plugins::*;

/// Provides the macro used for constructing rpc services and client stubs.
#[macro_use]
mod macros;
<commit_msg>Remove unused feature enablements from tarpc<commit_after>// Copyright 2018 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

//! tarpc is an RPC framework for rust with a focus on ease of use. Defining a
//! service can be done in just a few lines of code, and most of the boilerplate of
//! writing a server is taken care of for you.
//!
//! ## What is an RPC framework?
//! "RPC" stands for "Remote Procedure Call," a function call where the work of
//! producing the return value is being done somewhere else. When an rpc function is
//! invoked, behind the scenes the function contacts some other process somewhere
//! and asks them to evaluate the function instead. The original function then
//! returns the value produced by the other process.
//!
//! RPC frameworks are a fundamental building block of most microservices-oriented
//! architectures. Two well-known ones are [gRPC](http://www.grpc.io) and
//! [Cap'n Proto](https://capnproto.org/).
//!
//! tarpc differentiates itself from other RPC frameworks by defining the schema in code,
//! rather than in a separate language such as .proto. This means there's no separate compilation
//! process, and no cognitive context switching between different languages. Additionally, it
//! works with the community-backed library serde: any serde-serializable type can be used as
//! arguments to tarpc fns.
//!
//! ## Example
//!
//! Here's a small service.
//!
//! ```rust
//! #![feature(futures_api, pin, arbitrary_self_types, await_macro, async_await, proc_macro_hygiene)]
//!
//!
//! use futures::{
//!     compat::TokioDefaultSpawner,
//!     future::{self, Ready},
//!     prelude::*,
//! };
//! use tarpc::{
//!     client, context,
//!     server::{self, Handler},
//! };
//! use std::io;
//!
//! // This is the service definition. It looks a lot like a trait definition.
//! // It defines one RPC, hello, which takes one arg, name, and returns a String.
//! tarpc::service! {
//!     /// Returns a greeting for name.
//!     rpc hello(name: String) -> String;
//! }
//!
//! // This is the type that implements the generated Service trait. It is the business logic
//! // and is used to start the server.
//! #[derive(Clone)]
//! struct HelloServer;
//!
//! impl Service for HelloServer {
//!     // Each defined rpc generates two items in the trait, a fn that serves the RPC, and
//!     // an associated type representing the future output by the fn.
//!
//!     type HelloFut = Ready<String>;
//!
//!     fn hello(&self, _: context::Context, name: String) -> Self::HelloFut {
//!         future::ready(format!("Hello, {}!", name))
//!     }
//! }
//!
//! async fn run() -> io::Result<()> {
//!     // bincode_transport is provided by the associated crate bincode-transport. It makes it easy
//!     // to start up a serde-powered bincode serialization strategy over TCP.
//!     let transport = bincode_transport::listen(&"0.0.0.0:0".parse().unwrap())?;
//!     let addr = transport.local_addr();
//!
//!     // The server is configured with the defaults.
//!     let server = server::new(server::Config::default())
//!         // Server can listen on any type that implements the Transport trait.
//!         .incoming(transport)
//!         // Close the stream after the client connects
//!         .take(1)
//!         // serve is generated by the service! macro. It takes as input any type implementing
//!         // the generated Service trait.
//!         .respond_with(serve(HelloServer));
//!
//!     tokio_executor::spawn(server.unit_error().boxed().compat());
//!
//!     let transport = await!(bincode_transport::connect(&addr))?;
//!
//!     // new_stub is generated by the service! macro. Like Server, it takes a config and any
//!     // Transport as input, and returns a Client, also generated by the macro.
//!     // by the service mcro.
//!     let mut client = await!(new_stub(client::Config::default(), transport))?;
//!
//!     // The client has an RPC method for each RPC defined in service!. It takes the same args
//!     // as defined, with the addition of a Context, which is always the first arg. The Context
//!     // specifies a deadline and trace information which can be helpful in debugging requests.
//!     let hello = await!(client.hello(context::current(), "Stim".to_string()))?;
//!
//!     println!("{}", hello);
//!
//!     Ok(())
//! }
//!
//! fn main() {
//!     tarpc::init(TokioDefaultSpawner);
//!     tokio::run(run()
//!             .map_err(|e| eprintln!("Oh no: {}", e))
//!             .boxed()
//!             .compat(),
//!     );
//! }
//! ```

#![deny(missing_docs, missing_debug_implementations)]
#![feature(async_await)]
#![cfg_attr(
    test,
    feature(
        pin,
        futures_api,
        await_macro,
        proc_macro_hygiene,
        arbitrary_self_types
    )
)]

#[doc(hidden)]
pub use futures;
pub use rpc::*;
#[cfg(feature = "serde")]
#[doc(hidden)]
pub use serde;
#[doc(hidden)]
pub use tarpc_plugins::*;

/// Provides the macro used for constructing rpc services and client stubs.
#[macro_use]
mod macros;
<|endoftext|>


<commit_before>//! FFI functions to support Pact models.

use std::collections::BTreeMap;
use std::sync::Mutex;

use libc::c_char;
use maplit::btreemap;
use serde_json::Value;
use tracing::{error, warn};

use pact_models::{Consumer, Provider};
use pact_models::plugins::PluginData;
use pact_models::v4::interaction::interactions_from_json;
use pact_models::v4::pact::V4Pact;

use crate::{ffi_fn, safe_str};
use crate::util::ptr;

pub mod consumer;
pub mod message;
pub mod message_pact;
pub mod pact_specification;
pub mod provider;
pub mod provider_state;
pub mod iterators;
pub mod sync_message;
pub mod http_interaction;
pub mod expressions;
pub mod matching_rules;
pub mod generators;

/// Opaque type for use as a pointer to a Pact model
pub struct Pact {
  inner: Mutex<V4Pact>
}

impl Pact {
  pub fn new(pact: V4Pact) -> Self {
    Pact {
      inner: Mutex::new(pact)
    }
  }
}

ffi_fn! {
  /// Parses the provided JSON into a Pact model. The returned Pact model must be freed with the
  /// `pactffi_pact_model_delete` function when no longer needed.
  ///
  /// # Error Handling
  ///
  /// This function will return a NULL pointer if passed a NULL pointer or if an error occurs.
  fn pactffi_parse_pact_json(json: *const c_char) -> *mut Pact {
    let json_str = safe_str!(json);
    match serde_json::from_str::<Value>(json_str) {
      Ok(pact_json) => {
        // TODO: when pact_models 1.1.0 is released, update to this
        // let pact = V4Pact::pact_from_json(&pact_json, "<FFI>")?;
        let pact = pact_from_json(&pact_json, "<FFI>")?;
        ptr::raw_to(Pact::new(pact))
      },
      Err(err) => {
        error!("Failed to parse the Pact JSON - {}", err);
        ptr::null_mut_to::<Pact>()
      }
    }
  } {
    ptr::null_mut_to::<Pact>()
  }
}

ffi_fn! {
  /// Frees the memory used by the Pact model
  fn pactffi_pact_model_delete(pact: *mut Pact) {
    ptr::drop_raw(pact);
  }
}

// TODO: remove when pact_models 1.1.0 is released
fn pact_from_json(json: &Value, source: &str) -> anyhow::Result<V4Pact> {
  let mut metadata = meta_data_from_json(&json);

  let consumer = match json.get("consumer") {
    Some(v) => Consumer::from_json(v),
    None => Consumer { name: "consumer".into() }
  };
  let provider = match json.get("provider") {
    Some(v) => Provider::from_json(v),
    None => Provider { name: "provider".into() }
  };

  let plugin_data = extract_plugin_data(&mut metadata);

  Ok(V4Pact {
    consumer,
    provider,
    interactions: interactions_from_json(&json, source),
    metadata,
    plugin_data
  })
}

// TODO: remove when pact_models 1.1.0 is released
fn meta_data_from_json(pact_json: &Value) -> BTreeMap<String, Value> {
  match pact_json.get("metadata") {
    Some(Value::Object(ref obj)) => {
      obj.iter().map(|(k, v)| (k.clone(), v.clone())).collect()
    }
    _ => btreemap!{}
  }
}

// TODO: remove when pact_models 1.1.0 is released
fn extract_plugin_data(metadata: &mut BTreeMap<String, Value>) -> Vec<PluginData> {
  if let Some(plugin_data) = metadata.remove("plugins") {
    match plugin_data {
      Value::Array(items) => {
        let mut v = vec![];

        for item in &items {
          match serde_json::from_value::<PluginData>(item.clone()) {
            Ok(data) => v.push(data),
            Err(err) => warn!("Could not convert '{}' into PluginData format - {}", item, err)
          };
        }

        v
      }
      _ => {
        warn!("'{}' is not valid plugin data", plugin_data);
        vec![]
      }
    }
  } else {
    vec![]
  }
}

#[cfg(test)]
mod tests {
  use std::ffi::CString;

  use expectest::prelude::*;

  use crate::models::{pactffi_pact_model_delete, pactffi_parse_pact_json};

  #[test]
  fn load_pact_from_json() {
    let json = CString::new("{}").unwrap();
    let pact = pactffi_parse_pact_json(json.as_ptr());
    expect!(pact.is_null()).to(be_false());

    pactffi_pact_model_delete(pact);
  }
}
<commit_msg>chore: cleanup compiler warnings<commit_after>//! FFI functions to support Pact models.

use std::collections::BTreeMap;
use std::sync::Mutex;

use libc::c_char;
use maplit::btreemap;
use serde_json::Value;
use tracing::{error, warn};

use pact_models::{Consumer, Provider};
use pact_models::plugins::PluginData;
use pact_models::v4::interaction::interactions_from_json;
use pact_models::v4::pact::V4Pact;

use crate::{ffi_fn, safe_str};
use crate::util::ptr;

pub mod consumer;
pub mod message;
pub mod message_pact;
pub mod pact_specification;
pub mod provider;
pub mod provider_state;
pub mod iterators;
pub mod sync_message;
pub mod http_interaction;
pub mod expressions;
pub mod matching_rules;
pub mod generators;

/// Opaque type for use as a pointer to a Pact model
#[derive(Debug)]
pub struct Pact {
  inner: Mutex<V4Pact>
}

impl Pact {
  /// Create a new FFI Pact wrapper for the given Pact model
  pub fn new(pact: V4Pact) -> Self {
    Pact {
      inner: Mutex::new(pact)
    }
  }
}

ffi_fn! {
  /// Parses the provided JSON into a Pact model. The returned Pact model must be freed with the
  /// `pactffi_pact_model_delete` function when no longer needed.
  ///
  /// # Error Handling
  ///
  /// This function will return a NULL pointer if passed a NULL pointer or if an error occurs.
  fn pactffi_parse_pact_json(json: *const c_char) -> *mut Pact {
    let json_str = safe_str!(json);
    match serde_json::from_str::<Value>(json_str) {
      Ok(pact_json) => {
        // TODO: when pact_models 1.1.0 is released, update to this
        // let pact = V4Pact::pact_from_json(&pact_json, "<FFI>")?;
        let pact = pact_from_json(&pact_json, "<FFI>")?;
        ptr::raw_to(Pact::new(pact))
      },
      Err(err) => {
        error!("Failed to parse the Pact JSON - {}", err);
        ptr::null_mut_to::<Pact>()
      }
    }
  } {
    ptr::null_mut_to::<Pact>()
  }
}

ffi_fn! {
  /// Frees the memory used by the Pact model
  fn pactffi_pact_model_delete(pact: *mut Pact) {
    ptr::drop_raw(pact);
  }
}

// TODO: remove when pact_models 1.1.0 is released
fn pact_from_json(json: &Value, source: &str) -> anyhow::Result<V4Pact> {
  let mut metadata = meta_data_from_json(&json);

  let consumer = match json.get("consumer") {
    Some(v) => Consumer::from_json(v),
    None => Consumer { name: "consumer".into() }
  };
  let provider = match json.get("provider") {
    Some(v) => Provider::from_json(v),
    None => Provider { name: "provider".into() }
  };

  let plugin_data = extract_plugin_data(&mut metadata);

  Ok(V4Pact {
    consumer,
    provider,
    interactions: interactions_from_json(&json, source),
    metadata,
    plugin_data
  })
}

// TODO: remove when pact_models 1.1.0 is released
fn meta_data_from_json(pact_json: &Value) -> BTreeMap<String, Value> {
  match pact_json.get("metadata") {
    Some(Value::Object(ref obj)) => {
      obj.iter().map(|(k, v)| (k.clone(), v.clone())).collect()
    }
    _ => btreemap!{}
  }
}

// TODO: remove when pact_models 1.1.0 is released
fn extract_plugin_data(metadata: &mut BTreeMap<String, Value>) -> Vec<PluginData> {
  if let Some(plugin_data) = metadata.remove("plugins") {
    match plugin_data {
      Value::Array(items) => {
        let mut v = vec![];

        for item in &items {
          match serde_json::from_value::<PluginData>(item.clone()) {
            Ok(data) => v.push(data),
            Err(err) => warn!("Could not convert '{}' into PluginData format - {}", item, err)
          };
        }

        v
      }
      _ => {
        warn!("'{}' is not valid plugin data", plugin_data);
        vec![]
      }
    }
  } else {
    vec![]
  }
}

#[cfg(test)]
mod tests {
  use std::ffi::CString;

  use expectest::prelude::*;

  use crate::models::{pactffi_pact_model_delete, pactffi_parse_pact_json};

  #[test]
  fn load_pact_from_json() {
    let json = CString::new("{}").unwrap();
    let pact = pactffi_parse_pact_json(json.as_ptr());
    expect!(pact.is_null()).to(be_false());

    pactffi_pact_model_delete(pact);
  }
}
<|endoftext|>


<commit_before>use cairo;
use cairo_sys;
use glib::translate::*;
use libc;

use regex::{Captures, Regex};
use std::borrow::Cow;
use std::cell::RefCell;

use attributes::Attribute;
use drawing_ctx::{self, RsvgDrawingCtx};
use handle::RsvgHandle;
use node::*;
use property_bag::PropertyBag;

pub struct NodeLink {
    link: RefCell<Option<String>>,
}

impl NodeLink {
    pub fn new() -> NodeLink {
        NodeLink {
            link: RefCell::new(None),
        }
    }
}

impl NodeTrait for NodeLink {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag) -> NodeResult {
        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::XlinkHref => *self.link.borrow_mut() = Some(value.to_owned()),

                _ => (),
            }
        }

        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues,
        draw_ctx: *mut RsvgDrawingCtx,
        clipping: bool,
    ) {
        let link = self.link.borrow();

        let cascaded = CascadedValues::new(cascaded, node);
        let values = cascaded.get();

        drawing_ctx::push_discrete_layer(draw_ctx, values, clipping);

        if link.is_some() && link.as_ref().unwrap() != "" {
            const CAIRO_TAG_LINK: &str = "Link";

            let attributes = link.as_ref().map(|i| format!("uri='{}'", escape_value(i)));

            drawing_ctx::get_cairo_context(draw_ctx).with_tag(
                CAIRO_TAG_LINK,
                attributes.as_ref().map(|i| i.as_str()),
                || {
                    node.draw_children(&cascaded, draw_ctx, clipping);
                },
            )
        } else {
            node.draw_children(&cascaded, draw_ctx, clipping)
        }

        drawing_ctx::pop_discrete_layer(draw_ctx, node, values, clipping);
    }
}

/// escape quotes and backslashes with backslash
fn escape_value(value: &str) -> Cow<str> {
    lazy_static! {
        static ref REGEX: Regex = Regex::new(r"['\\]").unwrap();
    }

    REGEX.replace_all(value, |caps: &Captures| {
        match caps.get(0).unwrap().as_str() {
            "'" => "\\'".to_owned(),
            "\\" => "\\\\".to_owned(),
            _ => unreachable!(),
        }
    })
}

extern "C" {
    fn cairo_tag_begin(
        cr: *mut cairo_sys::cairo_t,
        tag_name: *const libc::c_char,
        attibutes: *const libc::c_char,
    );
    fn cairo_tag_end(cr: *mut cairo_sys::cairo_t, tag_name: *const libc::c_char);
}

/// Bindings that aren't supported by `cairo-rs` for now
trait CairoTagging {
    fn tag_begin(&self, tag_name: &str, attributes: Option<&str>);
    fn tag_end(&self, tag_name: &str);
    fn with_tag<U, T>(&self, tag_name: &str, attributes: Option<&str>, f: U) -> T
    where
        U: Fn() -> T,
    {
        self.tag_begin(tag_name, attributes);
        let result = f();
        self.tag_end(tag_name);

        result
    }
}

impl CairoTagging for cairo::Context {
    fn tag_begin(&self, tag_name: &str, attributes: Option<&str>) {
        unsafe {
            cairo_tag_begin(
                self.to_glib_none().0,
                tag_name.to_glib_none().0,
                attributes.to_glib_none().0,
            );
        }
    }

    fn tag_end(&self, tag_name: &str) {
        unsafe {
            cairo_tag_end(self.to_glib_none().0, tag_name.to_glib_none().0);
        }
    }
}
<commit_msg>link.rs: Use with_discrete_layer()<commit_after>use cairo;
use cairo_sys;
use glib::translate::*;
use libc;

use regex::{Captures, Regex};
use std::borrow::Cow;
use std::cell::RefCell;

use attributes::Attribute;
use drawing_ctx::{self, RsvgDrawingCtx};
use handle::RsvgHandle;
use node::*;
use property_bag::PropertyBag;

pub struct NodeLink {
    link: RefCell<Option<String>>,
}

impl NodeLink {
    pub fn new() -> NodeLink {
        NodeLink {
            link: RefCell::new(None),
        }
    }
}

impl NodeTrait for NodeLink {
    fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag) -> NodeResult {
        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::XlinkHref => *self.link.borrow_mut() = Some(value.to_owned()),

                _ => (),
            }
        }

        Ok(())
    }

    fn draw(
        &self,
        node: &RsvgNode,
        cascaded: &CascadedValues,
        draw_ctx: *mut RsvgDrawingCtx,
        clipping: bool,
    ) {
        let link = self.link.borrow();

        let cascaded = CascadedValues::new(cascaded, node);
        let values = cascaded.get();

        drawing_ctx::with_discrete_layer(draw_ctx, node, values, clipping, |_cr| {
            if link.is_some() && link.as_ref().unwrap() != "" {
                const CAIRO_TAG_LINK: &str = "Link";

                let attributes = link.as_ref().map(|i| format!("uri='{}'", escape_value(i)));

                drawing_ctx::get_cairo_context(draw_ctx).with_tag(
                    CAIRO_TAG_LINK,
                    attributes.as_ref().map(|i| i.as_str()),
                    || {
                        node.draw_children(&cascaded, draw_ctx, clipping);
                    },
                )
            } else {
                node.draw_children(&cascaded, draw_ctx, clipping)
            }
        });
    }
}

/// escape quotes and backslashes with backslash
fn escape_value(value: &str) -> Cow<str> {
    lazy_static! {
        static ref REGEX: Regex = Regex::new(r"['\\]").unwrap();
    }

    REGEX.replace_all(value, |caps: &Captures| {
        match caps.get(0).unwrap().as_str() {
            "'" => "\\'".to_owned(),
            "\\" => "\\\\".to_owned(),
            _ => unreachable!(),
        }
    })
}

extern "C" {
    fn cairo_tag_begin(
        cr: *mut cairo_sys::cairo_t,
        tag_name: *const libc::c_char,
        attibutes: *const libc::c_char,
    );
    fn cairo_tag_end(cr: *mut cairo_sys::cairo_t, tag_name: *const libc::c_char);
}

/// Bindings that aren't supported by `cairo-rs` for now
trait CairoTagging {
    fn tag_begin(&self, tag_name: &str, attributes: Option<&str>);
    fn tag_end(&self, tag_name: &str);
    fn with_tag<U, T>(&self, tag_name: &str, attributes: Option<&str>, f: U) -> T
    where
        U: Fn() -> T,
    {
        self.tag_begin(tag_name, attributes);
        let result = f();
        self.tag_end(tag_name);

        result
    }
}

impl CairoTagging for cairo::Context {
    fn tag_begin(&self, tag_name: &str, attributes: Option<&str>) {
        unsafe {
            cairo_tag_begin(
                self.to_glib_none().0,
                tag_name.to_glib_none().0,
                attributes.to_glib_none().0,
            );
        }
    }

    fn tag_end(&self, tag_name: &str) {
        unsafe {
            cairo_tag_end(self.to_glib_none().0, tag_name.to_glib_none().0);
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::{BTreeMap, BTreeSet};

#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum Foo {
    A(&'static str),
    _B,
    _C,
}

// Gather all references from a mutable iterator and make sure Miri notices if
// using them is dangerous.
fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator<Item = &'a mut T>) {
    // Gather all those references.
    let mut refs: Vec<&mut T> = iter.collect();
    // Use them all. Twice, to be sure we got all interleavings.
    for r in refs.iter_mut() {
        std::mem::swap(dummy, r);
    }
    for r in refs {
        std::mem::swap(dummy, r);
    }
}

pub fn main() {
    let mut b = BTreeSet::new();
    b.insert(Foo::A("\'"));
    b.insert(Foo::A("/="));
    b.insert(Foo::A("#"));
    b.insert(Foo::A("0o"));
    assert!(b.remove(&Foo::A("/=")));
    assert!(!b.remove(&Foo::A("/=")));

    // Also test a lower-alignment type, where the NodeHeader overlaps with
    // the keys.
    let mut b = BTreeSet::new();
    b.insert(1024u16);
    b.insert(7u16);

    let mut b = BTreeMap::new();
    b.insert(format!("bar"), 1024);
    b.insert(format!("baz"), 7);
    for i in 0..60 {
        b.insert(format!("key{}", i), i);
    }
    test_all_refs(&mut 13, b.values_mut());
}
<commit_msg>Auto merge of #1543 - RalfJung:btree, r=RalfJung<commit_after>#![feature(btree_drain_filter)]
use std::collections::{BTreeMap, BTreeSet};
use std::mem;

#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum Foo {
    A(&'static str),
    _B,
    _C,
}

// Gather all references from a mutable iterator and make sure Miri notices if
// using them is dangerous.
fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator<Item = &'a mut T>) {
    // Gather all those references.
    let mut refs: Vec<&mut T> = iter.collect();
    // Use them all. Twice, to be sure we got all interleavings.
    for r in refs.iter_mut() {
        std::mem::swap(dummy, r);
    }
    for r in refs {
        std::mem::swap(dummy, r);
    }
}

pub fn main() {
    let mut b = BTreeSet::new();
    b.insert(Foo::A("\'"));
    b.insert(Foo::A("/="));
    b.insert(Foo::A("#"));
    b.insert(Foo::A("0o"));
    assert!(b.remove(&Foo::A("/=")));
    assert!(!b.remove(&Foo::A("/=")));

    // Also test a lower-alignment type, where the NodeHeader overlaps with
    // the keys.
    let mut b = BTreeSet::new();
    b.insert(1024u16);
    b.insert(7u16);

    let mut b = BTreeMap::new();
    b.insert(format!("bar"), 1024);
    b.insert(format!("baz"), 7);
    for i in 0..60 {
        b.insert(format!("key{}", i), i);
    }
    test_all_refs(&mut 13, b.values_mut());

    // Test forgetting the drain.
    let mut d = b.drain_filter(|_, i| *i < 30);
    d.next().unwrap();
    mem::forget(d);
}
<|endoftext|>


<commit_before>// Copyright (c) 2020-present, Gregory Szorc
// All rights reserved.
//
// This software may be modified and distributed under the terms
// of the BSD license. See the LICENSE file for details.

use crate::ZstdError;
use cpython::{py_class, PyModule, PyObject, PyResult, Python, PythonObject};

py_class!(class ZstdCompressor |py| {
    def __new__(
        _cls,
        level: i32 = 3,
        dict_data: Option<PyObject> = None,
        compression_params: Option<PyObject> = None,
        write_checksum: Option<bool> = None,
        write_content_size: Option<bool> = None,
        write_dict_id: Option<bool> = None,
        threads: Option<i32> = None
    ) -> PyResult<PyObject> {
        ZstdCompressor::new_impl(
            py,
            level,
            dict_data,
            compression_params,
            write_checksum,
            write_content_size,
            write_dict_id,
            threads,
        )
    }
});

impl ZstdCompressor {
    fn new_impl(
        py: Python,
        level: i32,
        _dict_data: Option<PyObject>,
        _compression_params: Option<PyObject>,
        _write_checksum: Option<bool>,
        _write_content_size: Option<bool>,
        _write_dict_id: Option<bool>,
        _threads: Option<i32>,
    ) -> PyResult<PyObject> {
        if level > zstd_safe::max_c_level() {
            return Err(ZstdError::from_message(
                py,
                format!(
                    "level must be less than {}",
                    zstd_safe::max_c_level() as i32
                )
                .as_ref(),
            ));
        }

        let compressor = ZstdCompressor::create_instance(py)?;

        Ok(compressor.into_object())
    }
}

pub(crate) fn init_module(py: Python, module: &PyModule) -> PyResult<()> {
    module.add(py, "ZstdCompressor", py.get_type::<ZstdCompressor>())?;

    Ok(())
}
<commit_msg>rust: fix level validation<commit_after>// Copyright (c) 2020-present, Gregory Szorc
// All rights reserved.
//
// This software may be modified and distributed under the terms
// of the BSD license. See the LICENSE file for details.

use cpython::exc::ValueError;
use cpython::{py_class, PyErr, PyModule, PyObject, PyResult, Python, PythonObject};

py_class!(class ZstdCompressor |py| {
    def __new__(
        _cls,
        level: i32 = 3,
        dict_data: Option<PyObject> = None,
        compression_params: Option<PyObject> = None,
        write_checksum: Option<bool> = None,
        write_content_size: Option<bool> = None,
        write_dict_id: Option<bool> = None,
        threads: Option<i32> = None
    ) -> PyResult<PyObject> {
        ZstdCompressor::new_impl(
            py,
            level,
            dict_data,
            compression_params,
            write_checksum,
            write_content_size,
            write_dict_id,
            threads,
        )
    }
});

impl ZstdCompressor {
    fn new_impl(
        py: Python,
        level: i32,
        _dict_data: Option<PyObject>,
        _compression_params: Option<PyObject>,
        _write_checksum: Option<bool>,
        _write_content_size: Option<bool>,
        _write_dict_id: Option<bool>,
        _threads: Option<i32>,
    ) -> PyResult<PyObject> {
        if level > zstd_safe::max_c_level() {
            return Err(PyErr::new::<ValueError, _>(
                py,
                format!(
                    "level must be less than {}",
                    zstd_safe::max_c_level() as i32 + 1
                ),
            ));
        }

        let compressor = ZstdCompressor::create_instance(py)?;

        Ok(compressor.into_object())
    }
}

pub(crate) fn init_module(py: Python, module: &PyModule) -> PyResult<()> {
    module.add(py, "ZstdCompressor", py.get_type::<ZstdCompressor>())?;

    Ok(())
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::prelude::*;
use std::io::{BufReader, BufWriter};
use std::path::Path;

/// Receives a file as input
/// Writes the results table to output
/// Return value is number of correctly parsed games
pub fn tally(input: &Path, output: &Path) -> Result<usize, std::io::Error> {
    let file = try!{File::open(&input)};
    let file = BufReader::new(file);

    // stores Name => (MP, W, D, L, P)
    let mut game_state = HashMap::new();
    let mut lines = 0;

    for line in file.lines() {
        let line2 = try!{line};
        let split = line2.split(';');
        let tmp: Vec<&str> = split.collect();

        if tmp.len() != 3 {
            // ignore input line
            continue;
        }
        match tmp[2] {
            "draw" => {
                let t0 = tmp[0].to_string();
                let t1 = tmp[1].to_string();
                {
                    let mut team1 = game_state.entry(t0.to_string())
                        .or_insert((0, 0, 0, 0, 0));
                    (*team1).0 += 1;
                    (*team1).2 += 1;
                    (*team1).4 += 1;
                }
                {
                    let mut team2 = game_state.entry(t1.to_string())
                        .or_insert((0, 0, 0, 0, 0));
                    (*team2).0 += 1;
                    (*team2).2 += 1;
                    (*team2).4 += 1;
                }

            }
            "win" | "loss" => {
                // just swtich team order
                let (t0, t1) = if tmp[2] == "win" {
                    (tmp[0].to_string(), tmp[1].to_string())
                } else {
                    (tmp[1].to_string(), tmp[0].to_string())
                };

                {
                    let mut team1 = game_state.entry(t0.to_string())
                        .or_insert((0, 0, 0, 0, 0));
                    (*team1).0 += 1;
                    (*team1).1 += 1;
                    (*team1).4 += 3;
                }
                {
                    let mut team2 = game_state.entry(t1.to_string())
                        .or_insert((0, 0, 0, 0, 0));
                    (*team2).0 += 1;
                    (*team2).3 += 1;
                }
            }
            _ => {
                // ignore input line
                continue;
            }
        }
        lines += 1;
    }

    let mut game_state: Vec<_> =
        game_state.into_iter().map(|(team, (mp, w, d, l, p))| (team, mp, w, d, l, p)).collect();
    // convert to negative, because highest value should be sorted first
    game_state.sort_by_key(|&(ref team, _, w, _, _, p)| (-p, -w, team.to_string()));

    let file = try!{OpenOptions::new().write(true).open(&output)};
    let mut file = BufWriter::new(file);
    try!{writeln!(file, "{:<30} | {:>2} | {:>2} | {:>2} | {:>2} | {:>2}", "Team", "MP", "W", "D", "L", "P")};
    for (team, mp, w, d, l, p) in game_state {
        try!{writeln!(file, "{:<30} | {:>2} | {:>2} | {:>2} | {:>2} | {:>2}", team, mp, w, d, l, p)};
    }
    try!{file.flush()};
    Ok(lines)
}
<commit_msg>cleanup tournament, remove unnecessary values and shorten<commit_after>use std::collections::HashMap;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::prelude::*;
use std::io::{BufReader, BufWriter};
use std::path::Path;

/// Receives a file as input
/// Writes the results table to output
/// Return value is number of correctly parsed games
pub fn tally(input: &Path, output: &Path) -> Result<usize, std::io::Error> {
    let file = try!{File::open(&input)};
    let file = BufReader::new(file);

    // stores Name => (W, D, L)
    let mut game_state = HashMap::new();
    let mut lines = 0;

    for line in file.lines() {
        let line2 = try!{line};
        let split = line2.split(';');
        let tmp: Vec<&str> = split.collect();

        if tmp.len() != 3 {
            // ignore input line
            continue;
        }
        match tmp[2] {
            "draw" => {
                (*game_state.entry(tmp[0].to_string()).or_insert((0, 0, 0))).1 += 1;
                (*game_state.entry(tmp[1].to_string()).or_insert((0, 0, 0))).1 += 1;
            }
            "win" | "loss" => {
                // just swtich team order
                let (t0, t1) = if tmp[2] == "win" {
                    (tmp[0].to_string(), tmp[1].to_string())
                } else {
                    (tmp[1].to_string(), tmp[0].to_string())
                };
                (*game_state.entry(t0.to_string()).or_insert((0, 0, 0))).0 += 1;
                (*game_state.entry(t1.to_string()).or_insert((0, 0, 0))).2 += 1;
            }
            _ => {
                // ignore input line
                continue;
            }
        }
        // count number of valid lines
        lines += 1;
    }

    let mut game_state: Vec<_> =
        game_state.into_iter().map(|(team, (w, d, l))| (team, w, d, l)).collect();
    // convert to negative, because highest value should be sorted first
    game_state.sort_by_key(|&(ref team, w, d, _)| (-(3 * w + d), -w, team.to_string()));

    let file = try!{OpenOptions::new().write(true).open(&output)};
    let mut file = BufWriter::new(file);
    try!{writeln!(file, "{:<30} | {:>2} | {:>2} | {:>2} | {:>2} | {:>2}", "Team", "MP", "W", "D", "L", "P")};
    for (team, w, d, l) in game_state {
        try!{writeln!(file, "{:<30} | {:>2} | {:>2} | {:>2} | {:>2} | {:>2}", team, w+d+l, w, d, l, 3*w+d)};
    }
    try!{file.flush()};
    Ok(lines)
}
<|endoftext|>