<commit_before>#![feature(test)]

use compiletest_rs as compiletest;
extern crate test;

use std::env::{set_var, var};
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

#[must_use]
fn clippy_driver_path() -> PathBuf {
    if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
        PathBuf::from(path)
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/clippy-driver"))
    }
}

#[must_use]
fn host_libs() -> PathBuf {
    if let Some(path) = option_env!("HOST_LIBS") {
        PathBuf::from(path)
    } else {
        Path::new("target").join(env!("PROFILE"))
    }
}

#[must_use]
fn target_libs() -> Option<PathBuf> {
    option_env!("TARGET_LIBS").map(PathBuf::from)
}

#[must_use]
fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

#[must_use]
fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn config(mode: &str, dir: PathBuf) -> compiletest::Config {
    let mut config = compiletest::Config::default();

    let cfg_mode = mode.parse().expect("Invalid mode");
    if let Ok(name) = var::<&str>("TESTNAME") {
        config.filter = Some(name)
    }

    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }

    // When we'll want to use `extern crate ..` for a dependency that is used
    // both by the crate and the compiler itself, we can't simply pass -L flags
    // as we'll get a duplicate matching versions. Instead, disambiguate with
    // `--extern dep=path`.
    // See https://github.com/rust-lang/rust-clippy/issues/4015.
    let needs_disambiguation = ["serde", "regex", "clippy_lints"];
    // This assumes that deps are compiled (they are for Cargo integration tests).
    let deps = fs::read_dir(host_libs().join("deps")).unwrap();
    let deps: Vec<_> = if let Some(target_libs) = target_libs() {
        deps.chain(fs::read_dir(target_libs.join("deps")).unwrap()).collect()
    } else {
        deps.collect()
    };
    let disambiguated = deps
        .into_iter()
        .filter_map(|dep| {
            let path = dep.ok()?.path();
            let name = path.file_name()?.to_string_lossy();
            // NOTE: This only handles a single dep
            // https://github.com/laumann/compiletest-rs/issues/101
            needs_disambiguation.iter().find_map(|dep| {
                if name.starts_with(&format!("lib{}-", dep)) && name.ends_with(".rlib") {
                    Some(format!("--extern {}={}", dep, path.display()))
                } else {
                    None
                }
            })
        })
        .collect::<Vec<_>>();

    config.target_rustcflags = Some(format!(
        "-L {0} -L {0}/deps -Dwarnings -Zui-testing {1}",
        host_libs().display(),
        disambiguated.join(" ")
    ));

    config.mode = cfg_mode;
    config.build_base = if rustc_test_suite().is_some() {
        // we don't need access to the stderr files on travis
        let mut path = PathBuf::from(env!("OUT_DIR"));
        path.push("test_build_base");
        path
    } else {
        let mut path = std::env::current_dir().unwrap();
        path.push("target/debug/test_build_base");
        path
    };
    config.src_base = dir;
    config.rustc_path = clippy_driver_path();
    config
}

fn run_mode(mode: &str, dir: PathBuf) {
    let cfg = config(mode, dir);
    compiletest::run_tests(&cfg);
}

#[allow(clippy::identity_conversion)]
fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<test::TestDescAndFn>) -> Result<bool, io::Error> {
    let mut result = true;
    let opts = compiletest::test_opts(config);
    for dir in fs::read_dir(&config.src_base)? {
        let dir = dir?;
        if !dir.file_type()?.is_dir() {
            continue;
        }
        let dir_path = dir.path();
        set_var("CARGO_MANIFEST_DIR", &dir_path);
        for file in fs::read_dir(&dir_path)? {
            let file = file?;
            let file_path = file.path();
            if !file.file_type()?.is_file() {
                continue;
            }
            if file_path.extension() != Some(OsStr::new("rs")) {
                continue;
            }
            let paths = compiletest::common::TestPaths {
                file: file_path,
                base: config.src_base.clone(),
                relative_dir: dir_path.file_name().unwrap().into(),
            };
            let test_name = compiletest::make_test_name(&config, &paths);
            let index = tests
                .iter()
                .position(|test| test.desc.name == test_name)
                .expect("The test should be in there");
            result &= test::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
        }
    }
    Ok(result)
}

fn run_ui_toml() {
    let path = PathBuf::from("tests/ui-toml").canonicalize().unwrap();
    let config = config("ui", path);
    let tests = compiletest::make_tests(&config);

    let res = run_ui_toml_tests(&config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            println!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("CLIPPY_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    run_mode("ui", "tests/ui".into());
    run_ui_toml();
}
<commit_msg>Add target libs directory to search path<commit_after>#![feature(test)]

use compiletest_rs as compiletest;
extern crate test;

use std::env::{set_var, var};
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

#[must_use]
fn clippy_driver_path() -> PathBuf {
    if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
        PathBuf::from(path)
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/clippy-driver"))
    }
}

#[must_use]
fn host_libs() -> PathBuf {
    if let Some(path) = option_env!("HOST_LIBS") {
        PathBuf::from(path)
    } else {
        Path::new("target").join(env!("PROFILE"))
    }
}

#[must_use]
fn target_libs() -> Option<PathBuf> {
    option_env!("TARGET_LIBS").map(PathBuf::from)
}

#[must_use]
fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

#[must_use]
fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn config(mode: &str, dir: PathBuf) -> compiletest::Config {
    let mut config = compiletest::Config::default();

    let cfg_mode = mode.parse().expect("Invalid mode");
    if let Ok(name) = var::<&str>("TESTNAME") {
        config.filter = Some(name)
    }

    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }

    // When we'll want to use `extern crate ..` for a dependency that is used
    // both by the crate and the compiler itself, we can't simply pass -L flags
    // as we'll get a duplicate matching versions. Instead, disambiguate with
    // `--extern dep=path`.
    // See https://github.com/rust-lang/rust-clippy/issues/4015.
    let needs_disambiguation = ["serde", "regex", "clippy_lints"];
    // This assumes that deps are compiled (they are for Cargo integration tests).
    let deps = fs::read_dir(host_libs().join("deps")).unwrap();
    let deps: Vec<_> = if let Some(target_libs) = target_libs() {
        deps.chain(fs::read_dir(target_libs.join("deps")).unwrap()).collect()
    } else {
        deps.collect()
    };
    let disambiguated = deps
        .into_iter()
        .filter_map(|dep| {
            let path = dep.ok()?.path();
            let name = path.file_name()?.to_string_lossy();
            // NOTE: This only handles a single dep
            // https://github.com/laumann/compiletest-rs/issues/101
            needs_disambiguation.iter().find_map(|dep| {
                if name.starts_with(&format!("lib{}-", dep)) && name.ends_with(".rlib") {
                    Some(format!("--extern {}={}", dep, path.display()))
                } else {
                    None
                }
            })
        })
        .collect::<Vec<_>>();

    config.target_rustcflags = Some(format!(
        "-L {0} -L {0}/deps {1} -Dwarnings -Zui-testing {2}",
        host_libs().display(),
        target_libs().map_or_else(String::new, |path| format!("-L {0} -L {0}/deps", path.display())),
        disambiguated.join(" ")
    ));

    config.mode = cfg_mode;
    config.build_base = if rustc_test_suite().is_some() {
        // we don't need access to the stderr files on travis
        let mut path = PathBuf::from(env!("OUT_DIR"));
        path.push("test_build_base");
        path
    } else {
        let mut path = std::env::current_dir().unwrap();
        path.push("target/debug/test_build_base");
        path
    };
    config.src_base = dir;
    config.rustc_path = clippy_driver_path();
    config
}

fn run_mode(mode: &str, dir: PathBuf) {
    let cfg = config(mode, dir);
    compiletest::run_tests(&cfg);
}

#[allow(clippy::identity_conversion)]
fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<test::TestDescAndFn>) -> Result<bool, io::Error> {
    let mut result = true;
    let opts = compiletest::test_opts(config);
    for dir in fs::read_dir(&config.src_base)? {
        let dir = dir?;
        if !dir.file_type()?.is_dir() {
            continue;
        }
        let dir_path = dir.path();
        set_var("CARGO_MANIFEST_DIR", &dir_path);
        for file in fs::read_dir(&dir_path)? {
            let file = file?;
            let file_path = file.path();
            if !file.file_type()?.is_file() {
                continue;
            }
            if file_path.extension() != Some(OsStr::new("rs")) {
                continue;
            }
            let paths = compiletest::common::TestPaths {
                file: file_path,
                base: config.src_base.clone(),
                relative_dir: dir_path.file_name().unwrap().into(),
            };
            let test_name = compiletest::make_test_name(&config, &paths);
            let index = tests
                .iter()
                .position(|test| test.desc.name == test_name)
                .expect("The test should be in there");
            result &= test::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
        }
    }
    Ok(result)
}

fn run_ui_toml() {
    let path = PathBuf::from("tests/ui-toml").canonicalize().unwrap();
    let config = config("ui", path);
    let tests = compiletest::make_tests(&config);

    let res = run_ui_toml_tests(&config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            println!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("CLIPPY_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    run_mode("ui", "tests/ui".into());
    run_ui_toml();
}
<|endoftext|>


<commit_before>use crate::reflect::dynamic::map::DynamicMap;
use crate::reflect::reflect_eq::ReflectEq;
use crate::reflect::reflect_eq::ReflectEqMode;
use crate::reflect::ReflectValueBox;
use crate::reflect::ReflectValueRef;
use crate::reflect::RuntimeTypeBox;

mod generated;

/// Implemented for `HashMap` with appropriate keys and values
pub(crate) trait ReflectMap: Send + Sync + 'static {
    fn reflect_iter(&self) -> ReflectMapIter;

    fn len(&self) -> usize;

    fn is_empty(&self) -> bool;

    fn get<'a>(&'a self, key: ReflectValueRef) -> Option<ReflectValueRef<'a>>;

    fn insert(&mut self, key: ReflectValueBox, value: ReflectValueBox);

    fn clear(&mut self);

    fn key_type(&self) -> RuntimeTypeBox;

    fn value_type(&self) -> RuntimeTypeBox;
}

pub(crate) trait ReflectMapIterTrait<'a> {
    fn next(&mut self) -> Option<(ReflectValueRef<'a>, ReflectValueRef<'a>)>;
    fn key_type(&self) -> RuntimeTypeBox;
    fn value_type(&self) -> RuntimeTypeBox;
}

pub struct ReflectMapIter<'a> {
    imp: Box<dyn ReflectMapIterTrait<'a> + 'a>,
}

impl<'a> ReflectMapIter<'a> {
    pub(crate) fn new<I: ReflectMapIterTrait<'a> + 'a>(imp: I) -> ReflectMapIter<'a> {
        ReflectMapIter { imp: Box::new(imp) }
    }
}

impl<'a> Iterator for ReflectMapIter<'a> {
    type Item = (ReflectValueRef<'a>, ReflectValueRef<'a>);

    fn next(&mut self) -> Option<(ReflectValueRef<'a>, ReflectValueRef<'a>)> {
        self.imp.next()
    }
}

impl<'a> IntoIterator for &'a dyn ReflectMap {
    type Item = (ReflectValueRef<'a>, ReflectValueRef<'a>);
    type IntoIter = ReflectMapIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        self.reflect_iter()
    }
}

#[derive(Clone)]
enum ReflectMapRefImpl<'a> {
    Generated(&'a dyn ReflectMap),
    DynamicEmpty(DynamicMap),
}

/// Dynamic reference to `map` field
#[derive(Clone)] // TODO: add `Debug`
pub struct ReflectMapRef<'a> {
    imp: ReflectMapRefImpl<'a>,
}

/// Dynamic mutable reference to `map` field
pub struct ReflectMapMut<'a> {
    map: &'a mut dyn ReflectMap,
}

impl<'a> ReflectMapRef<'a> {
    pub(crate) fn new(map: &'a dyn ReflectMap) -> ReflectMapRef<'a> {
        ReflectMapRef {
            imp: ReflectMapRefImpl::Generated(map),
        }
    }

    pub(crate) fn new_empty(key: RuntimeTypeBox, value: RuntimeTypeBox) -> ReflectMapRef<'a> {
        ReflectMapRef {
            // TODO: this might be a bit expensive.
            imp: ReflectMapRefImpl::DynamicEmpty(DynamicMap::new(key, value)),
        }
    }

    /// Size of the map
    pub fn len(&self) -> usize {
        match &self.imp {
            ReflectMapRefImpl::Generated(map) => map.len(),
            ReflectMapRefImpl::DynamicEmpty(map) => map.len(),
        }
    }

    /// Is map empty?
    pub fn is_empty(&self) -> bool {
        match &self.imp {
            ReflectMapRefImpl::Generated(map) => map.is_empty(),
            ReflectMapRefImpl::DynamicEmpty(map) => map.is_empty(),
        }
    }

    /// Find a value by given key.
    pub fn get(&self, key: ReflectValueRef) -> Option<ReflectValueRef> {
        match &self.imp {
            ReflectMapRefImpl::Generated(map) => map.get(key),
            ReflectMapRefImpl::DynamicEmpty(map) => map.get(key),
        }
    }

    /// Map key type
    pub fn key_type(&self) -> RuntimeTypeBox {
        match &self.imp {
            ReflectMapRefImpl::Generated(map) => map.key_type(),
            ReflectMapRefImpl::DynamicEmpty(map) => map.key_type(),
        }
    }

    /// Map value type
    pub fn value_type(&self) -> RuntimeTypeBox {
        match &self.imp {
            ReflectMapRefImpl::Generated(map) => map.value_type(),
            ReflectMapRefImpl::DynamicEmpty(map) => map.value_type(),
        }
    }
}

impl<'a> ReflectEq for ReflectMapRef<'a> {
    fn reflect_eq(&self, that: &Self, mode: &ReflectEqMode) -> bool {
        let len = self.len();

        if len != that.len() {
            return false;
        }

        for (k, va) in self {
            let vb = match that.get(k) {
                Some(v) => v,
                None => return false,
            };

            if !va.reflect_eq(&vb, mode) {
                return false;
            }
        }

        true
    }
}

impl<'a> ReflectMapMut<'a> {
    pub(crate) fn new(map: &'a mut dyn ReflectMap) -> ReflectMapMut<'a> {
        ReflectMapMut { map }
    }

    fn as_ref(&'a self) -> ReflectMapRef<'a> {
        ReflectMapRef::new(self.map)
    }

    /// Map key type
    pub fn key_type(&self) -> RuntimeTypeBox {
        self.map.key_type()
    }

    /// Map value type
    pub fn value_type(&self) -> RuntimeTypeBox {
        self.map.value_type()
    }

    /// Number of map entries
    pub fn len(&self) -> usize {
        self.as_ref().len()
    }

    /// Is this map empty?
    pub fn is_empty(&self) -> bool {
        self.as_ref().is_empty()
    }

    /// Find a value for given key
    pub fn get(&self, key: ReflectValueRef) -> Option<ReflectValueRef> {
        self.map.get(key)
    }

    /// Insert a value into the map.
    ///
    /// # Panics
    ///
    /// If given key has an incompatible key type.
    pub fn insert(&mut self, key: ReflectValueBox, value: ReflectValueBox) {
        self.map.insert(key, value)
    }

    /// Clear
    pub fn clear(&mut self) {
        self.map.clear();
    }
}

/// Iterator over map
pub struct ReflectMapRefIter<'a> {
    iter: ReflectMapIter<'a>,
}

impl<'a> ReflectMapRefIter<'a> {
    fn _key_type(&self) -> RuntimeTypeBox {
        self.iter.imp.key_type()
    }

    fn _value_type(&self) -> RuntimeTypeBox {
        self.iter.imp.value_type()
    }
}

impl<'a> Iterator for ReflectMapRefIter<'a> {
    type Item = (ReflectValueRef<'a>, ReflectValueRef<'a>);

    fn next(&mut self) -> Option<(ReflectValueRef<'a>, ReflectValueRef<'a>)> {
        self.iter.next()
    }
}

impl<'a, 'b: 'a> IntoIterator for &'b ReflectMapRef<'a> {
    type Item = (ReflectValueRef<'a>, ReflectValueRef<'a>);
    type IntoIter = ReflectMapRefIter<'a>;

    fn into_iter(self) -> ReflectMapRefIter<'a> {
        match &self.imp {
            ReflectMapRefImpl::Generated(map) => ReflectMapRefIter {
                iter: map.reflect_iter(),
            },
            ReflectMapRefImpl::DynamicEmpty(map) => ReflectMapRefIter {
                iter: map.reflect_iter(),
            },
        }
    }
}
<commit_msg>Debug for ReflectMapRef<commit_after>use std::fmt::Debug;

use crate::reflect::dynamic::map::DynamicMap;
use crate::reflect::reflect_eq::ReflectEq;
use crate::reflect::reflect_eq::ReflectEqMode;
use crate::reflect::ReflectValueBox;
use crate::reflect::ReflectValueRef;
use crate::reflect::RuntimeTypeBox;

mod generated;

/// Implemented for `HashMap` with appropriate keys and values
pub(crate) trait ReflectMap: Debug + Send + Sync + 'static {
    fn reflect_iter(&self) -> ReflectMapIter;

    fn len(&self) -> usize;

    fn is_empty(&self) -> bool;

    fn get<'a>(&'a self, key: ReflectValueRef) -> Option<ReflectValueRef<'a>>;

    fn insert(&mut self, key: ReflectValueBox, value: ReflectValueBox);

    fn clear(&mut self);

    fn key_type(&self) -> RuntimeTypeBox;

    fn value_type(&self) -> RuntimeTypeBox;
}

pub(crate) trait ReflectMapIterTrait<'a> {
    fn next(&mut self) -> Option<(ReflectValueRef<'a>, ReflectValueRef<'a>)>;
    fn key_type(&self) -> RuntimeTypeBox;
    fn value_type(&self) -> RuntimeTypeBox;
}

pub struct ReflectMapIter<'a> {
    imp: Box<dyn ReflectMapIterTrait<'a> + 'a>,
}

impl<'a> ReflectMapIter<'a> {
    pub(crate) fn new<I: ReflectMapIterTrait<'a> + 'a>(imp: I) -> ReflectMapIter<'a> {
        ReflectMapIter { imp: Box::new(imp) }
    }
}

impl<'a> Iterator for ReflectMapIter<'a> {
    type Item = (ReflectValueRef<'a>, ReflectValueRef<'a>);

    fn next(&mut self) -> Option<(ReflectValueRef<'a>, ReflectValueRef<'a>)> {
        self.imp.next()
    }
}

impl<'a> IntoIterator for &'a dyn ReflectMap {
    type Item = (ReflectValueRef<'a>, ReflectValueRef<'a>);
    type IntoIter = ReflectMapIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        self.reflect_iter()
    }
}

#[derive(Clone, Debug)]
enum ReflectMapRefImpl<'a> {
    Generated(&'a dyn ReflectMap),
    DynamicEmpty(DynamicMap),
}

/// Dynamic reference to `map` field
#[derive(Clone, Debug)]
pub struct ReflectMapRef<'a> {
    imp: ReflectMapRefImpl<'a>,
}

/// Dynamic mutable reference to `map` field
pub struct ReflectMapMut<'a> {
    map: &'a mut dyn ReflectMap,
}

impl<'a> ReflectMapRef<'a> {
    pub(crate) fn new(map: &'a dyn ReflectMap) -> ReflectMapRef<'a> {
        ReflectMapRef {
            imp: ReflectMapRefImpl::Generated(map),
        }
    }

    pub(crate) fn new_empty(key: RuntimeTypeBox, value: RuntimeTypeBox) -> ReflectMapRef<'a> {
        ReflectMapRef {
            // TODO: this might be a bit expensive.
            imp: ReflectMapRefImpl::DynamicEmpty(DynamicMap::new(key, value)),
        }
    }

    /// Size of the map
    pub fn len(&self) -> usize {
        match &self.imp {
            ReflectMapRefImpl::Generated(map) => map.len(),
            ReflectMapRefImpl::DynamicEmpty(map) => map.len(),
        }
    }

    /// Is map empty?
    pub fn is_empty(&self) -> bool {
        match &self.imp {
            ReflectMapRefImpl::Generated(map) => map.is_empty(),
            ReflectMapRefImpl::DynamicEmpty(map) => map.is_empty(),
        }
    }

    /// Find a value by given key.
    pub fn get(&self, key: ReflectValueRef) -> Option<ReflectValueRef> {
        match &self.imp {
            ReflectMapRefImpl::Generated(map) => map.get(key),
            ReflectMapRefImpl::DynamicEmpty(map) => map.get(key),
        }
    }

    /// Map key type
    pub fn key_type(&self) -> RuntimeTypeBox {
        match &self.imp {
            ReflectMapRefImpl::Generated(map) => map.key_type(),
            ReflectMapRefImpl::DynamicEmpty(map) => map.key_type(),
        }
    }

    /// Map value type
    pub fn value_type(&self) -> RuntimeTypeBox {
        match &self.imp {
            ReflectMapRefImpl::Generated(map) => map.value_type(),
            ReflectMapRefImpl::DynamicEmpty(map) => map.value_type(),
        }
    }
}

impl<'a> ReflectEq for ReflectMapRef<'a> {
    fn reflect_eq(&self, that: &Self, mode: &ReflectEqMode) -> bool {
        let len = self.len();

        if len != that.len() {
            return false;
        }

        for (k, va) in self {
            let vb = match that.get(k) {
                Some(v) => v,
                None => return false,
            };

            if !va.reflect_eq(&vb, mode) {
                return false;
            }
        }

        true
    }
}

impl<'a> ReflectMapMut<'a> {
    pub(crate) fn new(map: &'a mut dyn ReflectMap) -> ReflectMapMut<'a> {
        ReflectMapMut { map }
    }

    fn as_ref(&'a self) -> ReflectMapRef<'a> {
        ReflectMapRef::new(self.map)
    }

    /// Map key type
    pub fn key_type(&self) -> RuntimeTypeBox {
        self.map.key_type()
    }

    /// Map value type
    pub fn value_type(&self) -> RuntimeTypeBox {
        self.map.value_type()
    }

    /// Number of map entries
    pub fn len(&self) -> usize {
        self.as_ref().len()
    }

    /// Is this map empty?
    pub fn is_empty(&self) -> bool {
        self.as_ref().is_empty()
    }

    /// Find a value for given key
    pub fn get(&self, key: ReflectValueRef) -> Option<ReflectValueRef> {
        self.map.get(key)
    }

    /// Insert a value into the map.
    ///
    /// # Panics
    ///
    /// If given key has an incompatible key type.
    pub fn insert(&mut self, key: ReflectValueBox, value: ReflectValueBox) {
        self.map.insert(key, value)
    }

    /// Clear
    pub fn clear(&mut self) {
        self.map.clear();
    }
}

/// Iterator over map
pub struct ReflectMapRefIter<'a> {
    iter: ReflectMapIter<'a>,
}

impl<'a> ReflectMapRefIter<'a> {
    fn _key_type(&self) -> RuntimeTypeBox {
        self.iter.imp.key_type()
    }

    fn _value_type(&self) -> RuntimeTypeBox {
        self.iter.imp.value_type()
    }
}

impl<'a> Iterator for ReflectMapRefIter<'a> {
    type Item = (ReflectValueRef<'a>, ReflectValueRef<'a>);

    fn next(&mut self) -> Option<(ReflectValueRef<'a>, ReflectValueRef<'a>)> {
        self.iter.next()
    }
}

impl<'a, 'b: 'a> IntoIterator for &'b ReflectMapRef<'a> {
    type Item = (ReflectValueRef<'a>, ReflectValueRef<'a>);
    type IntoIter = ReflectMapRefIter<'a>;

    fn into_iter(self) -> ReflectMapRefIter<'a> {
        match &self.imp {
            ReflectMapRefImpl::Generated(map) => ReflectMapRefIter {
                iter: map.reflect_iter(),
            },
            ReflectMapRefImpl::DynamicEmpty(map) => ReflectMapRefIter {
                iter: map.reflect_iter(),
            },
        }
    }
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use core::param::Param;
use core::trans::*;
use crypto::*;
use hyper::Client;
use hyper::client::Response;
use hyper::status::StatusCode;
use jsonrpc_types::response::*;
use serde_json;
use std::fmt;
use std::fs::File;
use std::io::Read;
use std::io::prelude::*;
use std::path::Path;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use std::sync::mpsc;
use std::thread;
use std::time;

static mut EXIT: bool = false;
#[allow(dead_code, unused_assignments)]
#[derive(Clone, Debug, PartialEq)]
pub enum Action {
    Create,
    Call,
    Store,
}

#[allow(dead_code, unused_assignments)]
#[derive(Clone, Debug)]
pub struct Sendtx {
    txnum: i32,
    threads: i32,
    pvfile: String,
    create: i32,
    ipandport: Vec<String>,
    code: String,
    first: Arc<Mutex<i32>>,
    totaltx: u64,
}

#[allow(dead_code, unused_variables, unused_assignments, non_snake_case, unused_mut)]
impl Sendtx {
    pub fn new(param: &Param) -> Self {
        //let (sync_send, sync_recv) = mpsc::channel();
        let totaltx = param.txnum * param.threads;
        let trans = Sendtx {
            txnum: param.txnum,
            threads: param.threads,
            pvfile: "".to_string(),
            create: 1,
            ipandport: param.ipandport.clone(),
            code: param.code.clone(),
            first: Arc::new(Mutex::new(0)),
            totaltx: totaltx as u64,
        };
        trans
    }

    pub fn generate_primacron(&self) -> Result<KeyPair, Error> {
        let path = Path::new(&self.pvfile);
        let mut file = match File::open(&path) {
            Ok(file) => file,
            Err(_) => panic!("open {:?} fail", path),
        };

        let mut contents = String::new();
        match file.read_to_string(&mut contents) {
            Err(_) => panic!("read fail "),
            Ok(_) => println!("read successfully.[{}]", contents),
        }
        let privkey = PrivKey::from_str(contents.as_str()).expect("privkey");
        KeyPair::from_privkey(privkey)
    }

    pub fn random_generation(&self) -> Result<KeyPair, Error> {
        Ok(KeyPair::gen_keypair())
    }

    pub fn send_data(&self, url: String, method: Methods) -> Result<Response, i32> {
        let client = Client::new();
        let data = Trans::generate_tx_data(method);
        if let Ok(res) = client.post(&url).body(&data).send() {
            Ok(res)
        } else {
            Err(-1)
        }
    }

    pub fn parse_response(res: &mut Response) -> (String, bool) {
        let mut buf = String::new();
        let mut ret = (String::new(), false);
        if let Ok(len) = (*res).read_to_string(&mut buf) {
            buf.truncate(len);
            if let Ok(deserialized) = serde_json::from_str(&buf) {
                let deserialized: RpcSuccess = deserialized;
                ret = match deserialized.result {
                    ResultBody::BlockNumber(hei) => (format!("{}", hei), true),
                    ResultBody::Transaction(RpcTransaction) => {
                        //let transaction = RpcTransaction.transaction;
                        let content = RpcTransaction.content;
                        if !content.vec().is_empty() {
                            (String::new(), true)
                        } else {
                            (String::new(), false)
                        }
                    }

                    ResultBody::FullBlock(full_block) => {
                        //let block = full_block.block;
                        let body = full_block.body;
                        let transactions = body.transactions;
                        (format!("{}", transactions.len()), true)
                    }

                    ResultBody::TxResponse(response) => {
                        if response.status == "Ok" {
                            let hash = response.hash;
                            (format!("{:?}", hash), true)
                        } else {
                            println!("cita_sendTransaction : {:?}", buf);
                            (String::new(), false)
                        }
                    }

                    ResultBody::Receipt(Receipt) => match Receipt.contract_address {
                        Some(contract_address) => (format!("{:?}", contract_address), true),
                        None => (String::new(), false),
                    },

                    _ => (String::new(), false),
                }
            } else {
                println!("jsonrpc response: {:?}", buf);
                ret = (String::new(), false);
            }
        }
        ret
    }

    pub fn send_tx(
        &self,
        action: Action,
        sync_send: mpsc::Sender<(u64, u64)>,
        send_h: mpsc::Sender<u64>,
        sender: String,
    ) {
        let mut sucess = 0;
        let mut fail = 0;
        let v_url = self.get_url();
        let num = v_url.len();
        let mut pos = 0;
        for index in 0..self.txnum {
            pos = (index as usize) % num;
            let url = v_url[pos].clone();
            let keypair = self.random_generation().unwrap();
            let frompv = keypair.privkey();
            let curh = self.get_height(url.clone());
            let tx = match action {
                Action::Create => Trans::generate_tx(&self.code, sender.clone(), frompv, curh),
                Action::Call => {
                    //读取合约地址
                    Trans::generate_tx(&self.code, sender.clone(), &frompv, curh)
                }
                Action::Store => Trans::generate_tx(&self.code, sender.clone(), frompv, curh),
            };
            {
                let mut firsttx = self.first.lock().unwrap();
                if *firsttx == 0 {
                    let curh = self.get_height(url.clone());
                    send_h.send(curh).unwrap();
                    *firsttx = 1;
                }
            }
            if let Ok(mut res) = self.send_data(url.clone(), Methods::Sendtx(tx)) {
                match res.status {
                    StatusCode::Ok => {
                        let parse_response = Self::parse_response(&mut res);
                        if parse_response.1 {
                            if action == Action::Create {
                                //存储返回hash
                                let path = Path::new("hash.txt");
                                let mut file = match File::create(&path) {
                                    Err(_) => panic!("create fail"),
                                    Ok(file) => file,
                                };

                                match file.write_all(parse_response.0.as_bytes()) {
                                    Err(_) => println!("write fail"),
                                    Ok(_) => (),
                                }
                            }
                            sucess = sucess + 1;
                        } else {
                            fail = fail + 1;
                        }
                    }
                    _ => {
                        println!("jsonrpc connect [{}] fail!", url);
                        fail = fail + 1;
                    }
                }
            } else {
                println!("jsonrpc connect [{}] fail!", url);
                fail = fail + 1;
            }
        }

        println!("sucess {}, fail {}", sucess, fail);
        //channel 发送sucess, fail
        let _ = sync_send.send((sucess, fail));
    }

    pub fn get_height(&self, url: String) -> u64 {
        let mut h = 0;
        if let Ok(mut res) = self.send_data(url.clone(), Methods::Height) {
            match res.status {
                StatusCode::Ok => {
                    let parse_response = Self::parse_response(&mut res);
                    if parse_response.1 {
                        h = u64::from_str(&(parse_response.0)).unwrap();
                    }
                }
                _ => panic!("jsonrpc connect fail!"),
            }
        }
        h
    }

    pub fn get_txnum_by_height(&self, url: String, h: u64) -> i32 {
        let mut num = -1;

        if let Ok(mut res) = self.send_data(url.clone(), Methods::Blockbyheiht(h)) {
            match res.status {
                StatusCode::Ok => {
                    let parse_response = Self::parse_response(&mut res);
                    if parse_response.1 {
                        num = i32::from_str(&(parse_response.0)).unwrap();
                    }
                }
                _ => num = -2,
            }
        }
        num
    }

    pub fn get_contract_address(&self) -> String {
        let mut address = "".to_string();
        let v_url = self.get_url();

        let mut file = match File::open("hash.txt") {
            Ok(file) => file,
            Err(_) => panic!("open [{}] fail", "hash.txt"),
        };

        let mut contents = String::new();
        match file.read_to_string(&mut contents) {
            Err(_) => panic!("read fail"),
            Ok(_) => println!("read hash.[{}]", contents),
        }

        for url in &v_url {
            if let Ok(mut res) = self.send_data(url.clone(), Methods::Receipt(contents.clone())) {
                match res.status {
                    StatusCode::Ok => {
                        let parse_response = Self::parse_response(&mut res);
                        if parse_response.1 {
                            address = parse_response.0;
                            break;
                        }
                    }
                    _ => (),
                }
            }
        }
        address
    }

    //创建合约线程

    pub fn dispatch_create_contracts_thd(
        &self,
        sync_send: mpsc::Sender<(u64, u64)>,
        send_h: mpsc::Sender<u64>,
        action: Action,
    ) {
        let sender = match action {
            Action::Create => "".to_string(),
            Action::Store => "ffffffffffffffffffffffffffffffffffffffff".to_string(),
            Action::Call => panic!("Action error"),
        };

        for index in 0..self.threads {
            let threadname = format!("create_contracts_thd #{}", index);
            let t = Arc::new(self.clone());
            let sync_send = sync_send.clone();
            let send_h = send_h.clone();
            let action = action.clone();
            let sender = sender.clone();
            let _ = thread::Builder::new().name(threadname).spawn(move || {
                t.send_tx(action, sync_send, send_h, sender);
            });
        }
    }

    //执行合约的交易线程
    pub fn dispatch_send_thd(&self, sync_send: mpsc::Sender<(u64, u64)>, send_h: mpsc::Sender<u64>) {
        //获取合约地址
        let sender = self.get_contract_address();

        for index in 0..self.threads {
            //发送交易
            //获取高度
            let threadname = format!("send_tx_thd #{}", index);
            let t = Arc::new(self.clone());
            let sync_send = sync_send.clone();
            let send_h = send_h.clone();
            let sender = sender.clone();
            let _ = thread::Builder::new().name(threadname).spawn(move || {
                t.send_tx(Action::Call, sync_send, send_h, sender);
            });
        }
    }

    pub fn analysitxinfo(&self, recv: mpsc::Receiver<(u64, u64)>, recvh: mpsc::Receiver<u64>) {
        let mut sucess = 0;
        let mut fail = 0;
        let s = Arc::new(self.clone());
        let v_url = self.get_url();
        let url_num = v_url.len();
        let mut pos = 0;
        let mut url = v_url[pos].clone();
        let _ = thread::Builder::new()
            .name("analysistransinfo".into())
            .spawn(move || {
                let mut flag = 0;
                let mut txnum = 0;
                let mut starth = 0;
                let mut endh = 0;
                let mut sys_time = time::SystemTime::now();
                let cl = s.clone();
                loop {
                    match endh {
                        0 => {
                            //endh = cl.get_height(url.clone());
                            let h = recvh.recv_timeout(time::Duration::new(0, 0));

                            if h.is_ok() {
                                endh = h.unwrap();
                                println!("================== {}", endh);
                            }
                            sys_time = time::SystemTime::now();
                        }
                        _ => {
                            let blocknum = cl.get_txnum_by_height(url.clone(), endh);
                            if blocknum >= 0 {
                                if blocknum > 0 && starth == 0 {
                                    starth = endh;
                                }
                                endh = endh + 1;
                                txnum = txnum + blocknum;
                                println!(
                                    "current tx num: {}, use time:{}s",
                                    txnum,
                                    sys_time.elapsed().unwrap().as_secs()
                                );
                            } else if blocknum == -2 {
                                pos += 1;
                            }
                        }
                    }

                    match pos {
                        x if x < url_num => url = v_url[pos].clone(),
                        _ => panic!("connect jsonrpc fail"),
                    }

                    let notify = recv.recv_timeout(time::Duration::new(0, 0));
                    if notify.is_ok() {
                        sucess = notify.unwrap().0;
                        fail = notify.unwrap().1;
                    }

                    if (sucess + fail) >= s.totaltx as u64 && txnum as u64 >= sucess {
                        unsafe {
                            EXIT = true;
                        }
                        break;
                    }
                    thread::sleep(time::Duration::new(0, 100));
                }
                println!(
                    "send tx num:{}, start h:{}, end h:{}, Total time:{}s",
                    txnum,
                    starth,
                    endh,
                    sys_time.elapsed().unwrap().as_secs()
                );
            });
    }

    pub fn get_url(&self) -> Vec<String> {
        let mut vurl = Vec::new();
        for ipandport in &self.ipandport {
            let v: Vec<&str> = ipandport.split(":").collect();
            let url = fmt::format(format_args!("http://{}:{}", v[0], v[1]));
            vurl.push(url);
        }
        vurl
    }

    pub fn start(&self, category: u8) {
        let (sync_send, sync_recv) = mpsc::channel();
        let (send_h, recv_h) = mpsc::channel();
        let (send, recv) = mpsc::channel();

        match category {
            1 => self.dispatch_create_contracts_thd(sync_send, send_h, Action::Create),
            2 => self.dispatch_send_thd(sync_send, send_h),
            3 | _ => self.dispatch_create_contracts_thd(sync_send, send_h, Action::Store),
        }

        //通过高度获取交易是块交易的数量
        self.analysitxinfo(recv, recv_h);

        //发送完成输出完成的总数
        //jsonrpc返回成功的数量==入块的成功数退出循环
        Self::wait(self.totaltx, sync_recv, send);
    }

    fn wait(totaltx: u64, sync_recv: mpsc::Receiver<(u64, u64)>, send: mpsc::Sender<(u64, u64)>) {
        let mut sucess = 0;
        let mut fail = 0;
        let sys_time = time::SystemTime::now();

        loop {
            let notify = sync_recv.recv_timeout(time::Duration::new(1, 0));
            if notify.is_ok() {
                sucess += notify.unwrap().0;
                fail += notify.unwrap().1;
                if (sucess + fail) >= totaltx {
                    send.send((sucess, fail)).unwrap();
                    println!(
                        " jsonrpc use time:{}s",
                        sys_time.elapsed().unwrap().as_secs()
                    );
                    println!("write successfully.[{}]", sucess);
                }
            }
            unsafe {
                if EXIT {
                    break;
                }
            }
            thread::sleep(time::Duration::new(0, 100));
        }
    }
}
<commit_msg>Fixed send trans<commit_after>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use core::param::Param;
use core::trans::*;
use crypto::*;
use hyper::Client;
use hyper::client::Response;
use hyper::status::StatusCode;
use jsonrpc_types::response::*;
use serde_json;
use std::fmt;
use std::fs::File;
use std::io::Read;
use std::io::prelude::*;
use std::path::Path;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use std::sync::mpsc;
use std::thread;
use std::time;

static mut EXIT: bool = false;
#[allow(dead_code, unused_assignments)]
#[derive(Clone, Debug, PartialEq)]
pub enum Action {
    Create,
    Call,
    Store,
}

#[allow(dead_code, unused_assignments)]
#[derive(Clone, Debug)]
pub struct Sendtx {
    txnum: i32,
    threads: i32,
    pvfile: String,
    create: i32,
    ipandport: Vec<String>,
    code: String,
    first: Arc<Mutex<i32>>,
    totaltx: u64,
}

#[allow(dead_code, unused_variables, unused_assignments, non_snake_case, unused_mut)]
impl Sendtx {
    pub fn new(param: &Param) -> Self {
        //let (sync_send, sync_recv) = mpsc::channel();
        let totaltx = param.txnum * param.threads;
        let trans = Sendtx {
            txnum: param.txnum,
            threads: param.threads,
            pvfile: "".to_string(),
            create: 1,
            ipandport: param.ipandport.clone(),
            code: param.code.clone(),
            first: Arc::new(Mutex::new(0)),
            totaltx: totaltx as u64,
        };
        trans
    }

    pub fn generate_primacron(&self) -> Result<KeyPair, Error> {
        let path = Path::new(&self.pvfile);
        let mut file = match File::open(&path) {
            Ok(file) => file,
            Err(_) => panic!("open {:?} fail", path),
        };

        let mut contents = String::new();
        match file.read_to_string(&mut contents) {
            Err(_) => panic!("read fail "),
            Ok(_) => println!("read successfully.[{}]", contents),
        }
        let privkey = PrivKey::from_str(contents.as_str()).expect("privkey");
        KeyPair::from_privkey(privkey)
    }

    pub fn random_generation(&self) -> Result<KeyPair, Error> {
        Ok(KeyPair::gen_keypair())
    }

    pub fn send_data(&self, url: String, method: Methods) -> Result<Response, i32> {
        let client = Client::new();
        let data = Trans::generate_tx_data(method);
        if let Ok(res) = client.post(&url).body(&data).send() {
            Ok(res)
        } else {
            Err(-1)
        }
    }

    pub fn parse_response(res: &mut Response) -> (String, bool) {
        let mut buf = String::new();
        let mut ret = (String::new(), false);
        if let Ok(len) = (*res).read_to_string(&mut buf) {
            buf.truncate(len);
            if let Ok(deserialized) = serde_json::from_str(&buf) {
                let deserialized: RpcSuccess = deserialized;
                ret = match deserialized.result {
                    ResultBody::BlockNumber(hei) => (format!("{}", hei), true),
                    ResultBody::Transaction(RpcTransaction) => {
                        //let transaction = RpcTransaction.transaction;
                        let content = RpcTransaction.content;
                        if !content.vec().is_empty() {
                            (String::new(), true)
                        } else {
                            (String::new(), false)
                        }
                    }

                    ResultBody::FullBlock(full_block) => {
                        //let block = full_block.block;
                        let body = full_block.body;
                        let transactions = body.transactions;
                        (format!("{}", transactions.len()), true)
                    }

                    ResultBody::TxResponse(response) => {
                        if response.status == "OK" {
                            let hash = response.hash;
                            (format!("{:?}", hash), true)
                        } else {
                            println!("cita_sendTransaction : {:?}", buf);
                            (String::new(), false)
                        }
                    }

                    ResultBody::Receipt(Receipt) => match Receipt.contract_address {
                        Some(contract_address) => (format!("{:?}", contract_address), true),
                        None => (String::new(), false),
                    },

                    _ => (String::new(), false),
                }
            } else {
                println!("jsonrpc response: {:?}", buf);
                ret = (String::new(), false);
            }
        }
        ret
    }

    pub fn send_tx(
        &self,
        action: Action,
        sync_send: mpsc::Sender<(u64, u64)>,
        send_h: mpsc::Sender<u64>,
        sender: String,
    ) {
        let mut sucess = 0;
        let mut fail = 0;
        let v_url = self.get_url();
        let num = v_url.len();
        let mut pos = 0;
        for index in 0..self.txnum {
            pos = (index as usize) % num;
            let url = v_url[pos].clone();
            let keypair = self.random_generation().unwrap();
            let frompv = keypair.privkey();
            let curh = self.get_height(url.clone());
            let tx = match action {
                Action::Create => Trans::generate_tx(&self.code, sender.clone(), frompv, curh),
                Action::Call => {
                    //读取合约地址
                    Trans::generate_tx(&self.code, sender.clone(), &frompv, curh)
                }
                Action::Store => Trans::generate_tx(&self.code, sender.clone(), frompv, curh),
            };
            {
                let mut firsttx = self.first.lock().unwrap();
                if *firsttx == 0 {
                    let curh = self.get_height(url.clone());
                    send_h.send(curh).unwrap();
                    *firsttx = 1;
                }
            }
            if let Ok(mut res) = self.send_data(url.clone(), Methods::Sendtx(tx)) {
                match res.status {
                    StatusCode::Ok => {
                        let parse_response = Self::parse_response(&mut res);
                        if parse_response.1 {
                            if action == Action::Create {
                                //存储返回hash
                                let path = Path::new("hash.txt");
                                let mut file = match File::create(&path) {
                                    Err(_) => panic!("create fail"),
                                    Ok(file) => file,
                                };

                                match file.write_all(parse_response.0.as_bytes()) {
                                    Err(_) => println!("write fail"),
                                    Ok(_) => (),
                                }
                            }
                            sucess = sucess + 1;
                        } else {
                            fail = fail + 1;
                        }
                    }
                    _ => {
                        println!("jsonrpc connect [{}] fail!", url);
                        fail = fail + 1;
                    }
                }
            } else {
                println!("jsonrpc connect [{}] fail!", url);
                fail = fail + 1;
            }
        }

        println!("sucess {}, fail {}", sucess, fail);
        //channel 发送sucess, fail
        let _ = sync_send.send((sucess, fail));
    }

    pub fn get_height(&self, url: String) -> u64 {
        let mut h = 0;
        if let Ok(mut res) = self.send_data(url.clone(), Methods::Height) {
            match res.status {
                StatusCode::Ok => {
                    let parse_response = Self::parse_response(&mut res);
                    if parse_response.1 {
                        h = u64::from_str(&(parse_response.0)).unwrap();
                    }
                }
                _ => panic!("jsonrpc connect fail!"),
            }
        }
        h
    }

    pub fn get_txnum_by_height(&self, url: String, h: u64) -> i32 {
        let mut num = -1;

        if let Ok(mut res) = self.send_data(url.clone(), Methods::Blockbyheiht(h)) {
            match res.status {
                StatusCode::Ok => {
                    let parse_response = Self::parse_response(&mut res);
                    if parse_response.1 {
                        num = i32::from_str(&(parse_response.0)).unwrap();
                    }
                }
                _ => num = -2,
            }
        }
        num
    }

    pub fn get_contract_address(&self) -> String {
        let mut address = "".to_string();
        let v_url = self.get_url();

        let mut file = match File::open("hash.txt") {
            Ok(file) => file,
            Err(_) => panic!("open [{}] fail", "hash.txt"),
        };

        let mut contents = String::new();
        match file.read_to_string(&mut contents) {
            Err(_) => panic!("read fail"),
            Ok(_) => println!("read hash.[{}]", contents),
        }

        for url in &v_url {
            if let Ok(mut res) = self.send_data(url.clone(), Methods::Receipt(contents.clone())) {
                match res.status {
                    StatusCode::Ok => {
                        let parse_response = Self::parse_response(&mut res);
                        if parse_response.1 {
                            address = parse_response.0;
                            break;
                        }
                    }
                    _ => (),
                }
            }
        }
        address
    }

    //创建合约线程

    pub fn dispatch_create_contracts_thd(
        &self,
        sync_send: mpsc::Sender<(u64, u64)>,
        send_h: mpsc::Sender<u64>,
        action: Action,
    ) {
        let sender = match action {
            Action::Create => "".to_string(),
            Action::Store => "ffffffffffffffffffffffffffffffffffffffff".to_string(),
            Action::Call => panic!("Action error"),
        };

        for index in 0..self.threads {
            let threadname = format!("create_contracts_thd #{}", index);
            let t = Arc::new(self.clone());
            let sync_send = sync_send.clone();
            let send_h = send_h.clone();
            let action = action.clone();
            let sender = sender.clone();
            let _ = thread::Builder::new().name(threadname).spawn(move || {
                t.send_tx(action, sync_send, send_h, sender);
            });
        }
    }

    //执行合约的交易线程
    pub fn dispatch_send_thd(&self, sync_send: mpsc::Sender<(u64, u64)>, send_h: mpsc::Sender<u64>) {
        //获取合约地址
        let sender = self.get_contract_address();

        for index in 0..self.threads {
            //发送交易
            //获取高度
            let threadname = format!("send_tx_thd #{}", index);
            let t = Arc::new(self.clone());
            let sync_send = sync_send.clone();
            let send_h = send_h.clone();
            let sender = sender.clone();
            let _ = thread::Builder::new().name(threadname).spawn(move || {
                t.send_tx(Action::Call, sync_send, send_h, sender);
            });
        }
    }

    pub fn analysitxinfo(&self, recv: mpsc::Receiver<(u64, u64)>, recvh: mpsc::Receiver<u64>) {
        let mut sucess = 0;
        let mut fail = 0;
        let s = Arc::new(self.clone());
        let v_url = self.get_url();
        let url_num = v_url.len();
        let mut pos = 0;
        let mut url = v_url[pos].clone();
        let _ = thread::Builder::new()
            .name("analysistransinfo".into())
            .spawn(move || {
                let mut flag = 0;
                let mut txnum = 0;
                let mut starth = 0;
                let mut endh = 0;
                let mut sys_time = time::SystemTime::now();
                let cl = s.clone();
                loop {
                    match endh {
                        0 => {
                            //endh = cl.get_height(url.clone());
                            let h = recvh.recv_timeout(time::Duration::new(0, 0));

                            if h.is_ok() {
                                endh = h.unwrap();
                                println!("================== {}", endh);
                            }
                            sys_time = time::SystemTime::now();
                        }
                        _ => {
                            let blocknum = cl.get_txnum_by_height(url.clone(), endh);
                            if blocknum >= 0 {
                                if blocknum > 0 && starth == 0 {
                                    starth = endh;
                                }
                                endh = endh + 1;
                                txnum = txnum + blocknum;
                                println!(
                                    "current tx num: {}, use time:{}s",
                                    txnum,
                                    sys_time.elapsed().unwrap().as_secs()
                                );
                            } else if blocknum == -2 {
                                pos += 1;
                            }
                        }
                    }

                    match pos {
                        x if x < url_num => url = v_url[pos].clone(),
                        _ => panic!("connect jsonrpc fail"),
                    }

                    let notify = recv.recv_timeout(time::Duration::new(0, 0));
                    if notify.is_ok() {
                        sucess = notify.unwrap().0;
                        fail = notify.unwrap().1;
                    }

                    if (sucess + fail) >= s.totaltx as u64 && txnum as u64 >= sucess {
                        unsafe {
                            EXIT = true;
                        }
                        break;
                    }
                    thread::sleep(time::Duration::new(0, 100));
                }
                println!(
                    "send tx num:{}, start h:{}, end h:{}, Total time:{}s",
                    txnum,
                    starth,
                    endh,
                    sys_time.elapsed().unwrap().as_secs()
                );
            });
    }

    pub fn get_url(&self) -> Vec<String> {
        let mut vurl = Vec::new();
        for ipandport in &self.ipandport {
            let v: Vec<&str> = ipandport.split(":").collect();
            let url = fmt::format(format_args!("http://{}:{}", v[0], v[1]));
            vurl.push(url);
        }
        vurl
    }

    pub fn start(&self, category: u8) {
        let (sync_send, sync_recv) = mpsc::channel();
        let (send_h, recv_h) = mpsc::channel();
        let (send, recv) = mpsc::channel();

        match category {
            1 => self.dispatch_create_contracts_thd(sync_send, send_h, Action::Create),
            2 => self.dispatch_send_thd(sync_send, send_h),
            3 | _ => self.dispatch_create_contracts_thd(sync_send, send_h, Action::Store),
        }

        //通过高度获取交易是块交易的数量
        self.analysitxinfo(recv, recv_h);

        //发送完成输出完成的总数
        //jsonrpc返回成功的数量==入块的成功数退出循环
        Self::wait(self.totaltx, sync_recv, send);
    }

    fn wait(totaltx: u64, sync_recv: mpsc::Receiver<(u64, u64)>, send: mpsc::Sender<(u64, u64)>) {
        let mut sucess = 0;
        let mut fail = 0;
        let sys_time = time::SystemTime::now();

        loop {
            let notify = sync_recv.recv_timeout(time::Duration::new(1, 0));
            if notify.is_ok() {
                sucess += notify.unwrap().0;
                fail += notify.unwrap().1;
                if (sucess + fail) >= totaltx {
                    send.send((sucess, fail)).unwrap();
                    println!(
                        " jsonrpc use time:{}s",
                        sys_time.elapsed().unwrap().as_secs()
                    );
                    println!("write successfully.[{}]", sucess);
                }
            }
            unsafe {
                if EXIT {
                    break;
                }
            }
            thread::sleep(time::Duration::new(0, 100));
        }
    }
}
<|endoftext|>


<commit_before>mod utils;

use js_sys::Float64Array;
use nalgebra::base::*;
use rand::distributions::Uniform;
use rand::rngs::SmallRng;
use rand::SeedableRng;
use std::vec::Vec;
use wasm_bindgen::prelude::*;
use web_sys::console;

// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

#[wasm_bindgen]
pub struct SvdResult {
    u: Vec<f64>,
    singular_values: Vec<f64>,
    v_t: Vec<f64>,
}

#[wasm_bindgen]
impl SvdResult {
    fn new(u: DMatrix<f64>, singular_values: DVector<f64>, v_t: DMatrix<f64>) -> SvdResult {
        SvdResult {
            u: u.data.into(),
            singular_values: singular_values.data.into(),
            v_t: v_t.data.into(),
        }
    }
    pub fn u(&self) -> Float64Array {
        unsafe {
            return Float64Array::view(&self.u);
        }
    }
    pub fn singular_values(&self) -> Float64Array {
        unsafe {
            return Float64Array::view(&self.singular_values);
        }
    }
    pub fn v_t(&self) -> Float64Array {
        unsafe {
            return Float64Array::view(&self.v_t);
        }
    }
}

// TODO: Sort singular values descending
// not done by default, see https://github.com/dimforge/nalgebra/issues/349

#[wasm_bindgen]
pub fn svd(a_data: &[f64], nrows: usize, ncols: usize) -> SvdResult {
    let a = DMatrix::from_column_slice(nrows, ncols, a_data);
    console::time_with_label("computation of SVD");
    let svd = a.svd(true, true);
    console::time_end_with_label("computation of SVD");
    return SvdResult::new(svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap());
}

// Randomized algorithm that calculates the truncated SVD
// technique based on https://research.fb.com/fast-randomized-svd/
// Precondition: t <= MIN(nrows, ncols)
#[wasm_bindgen]
pub fn svd_simple_approx(a_data: &[f64], nrows: usize, ncols: usize, t: usize) -> SvdResult {
    console::log_1(&JsValue::from_str("test log"));
    let a = DMatrix::from_column_slice(nrows, ncols, a_data);

    console::time_with_label("computation of approximate SVD");

    // Generate matrix Ω ∈ ℝ^{m × n}
    let mut rng = SmallRng::seed_from_u64(2342);
    let distr = Uniform::new(-1.0, 1.0);
    let omega: DMatrix<f64> = DMatrix::from_distribution(ncols, t, &distr, &mut rng);

    // Compute Y = A Ω
    let y = (&a) * omega;

    // Compute the QR decomposition of Y, Y = Q R
    let q = y.qr().q();

    // Compute B = Qᵀ A
    let b = q.tr_mul(&a);

    // Compute the SVD of B
    let b_svd = b.svd(true, true);

    let u = q * b_svd.u.unwrap();

    console::time_end_with_label("computation of approximate SVD");

    return SvdResult::new(u, b_svd.singular_values, b_svd.v_t.unwrap());
}
<commit_msg>Sort SVD (fixes #19)<commit_after>mod utils;

use js_sys::Float64Array;
use nalgebra::base::*;
use nalgebra::linalg::SVD;
use rand::distributions::Uniform;
use rand::rngs::SmallRng;
use rand::SeedableRng;
use std::vec::Vec;
use wasm_bindgen::prelude::*;
use web_sys::console;

// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

#[wasm_bindgen]
pub struct SvdResult {
    u: Vec<f64>,
    singular_values: Vec<f64>,
    v_t: Vec<f64>,
}

#[wasm_bindgen]
impl SvdResult {
    fn new(u: DMatrix<f64>, singular_values: DVector<f64>, v_t: DMatrix<f64>) -> SvdResult {
        SvdResult {
            u: u.data.into(),
            singular_values: singular_values.data.into(),
            v_t: v_t.data.into(),
        }
    }
    pub fn u(&self) -> Float64Array {
        unsafe {
            return Float64Array::view(&self.u);
        }
    }
    pub fn singular_values(&self) -> Float64Array {
        unsafe {
            return Float64Array::view(&self.singular_values);
        }
    }
    pub fn v_t(&self) -> Float64Array {
        unsafe {
            return Float64Array::view(&self.v_t);
        }
    }
}

fn permute_columns<T>(mat: &mut DMatrix<f64>, perm: &Vec<(T, usize)>) {
    assert!(mat.ncols() == perm.len());
    let n = mat.ncols();
    let mut already_permuted = vec![0; n]; // TODO: use bitvector?
    for i in 0..n {
        if already_permuted[i] == 0 {
            let (mut j, mut k) = (i, perm[i].1);
            while k != i {
                mat.swap_columns(j, k);
                already_permuted[k] = 1;
                j = k;
                k = perm[k].1;
            }
            already_permuted[i] = 1;
        }
    }
}

fn permute_rows<T>(mat: &mut DMatrix<f64>, perm: &Vec<(T, usize)>) {
    assert!(mat.nrows() == perm.len());
    let n = mat.nrows();
    let mut already_permuted = vec![0; n]; // TODO: use bitvector?
    for i in 0..n {
        if already_permuted[i] == 0 {
            let (mut j, mut k) = (i, perm[i].1);
            while k != i {
                mat.swap_rows(j, k);
                already_permuted[k] = 1;
                j = k;
                k = perm[k].1;
            }
            already_permuted[i] = 1;
        }
    }
}

// We have to sort SVD because this is not done by default,
// see https://github.com/dimforge/nalgebra/issues/349
fn sort_svd(svd: &mut SVD<f64, Dynamic, Dynamic>) {
    let mut s: Vec<(_, _)> = svd
        .singular_values
        .into_iter()
        .enumerate()
        .map(|(idx, &v)| (v, idx))
        .collect();
    s.sort_unstable_by(|a, b| b.partial_cmp(a).unwrap());
    match svd.u.iter_mut().next() {
        Some(u) => permute_columns(u, &s),
        None => {}
    }
    match svd.v_t.iter_mut().next() {
        Some(v_t) => permute_rows(v_t, &s),
        None => {}
    }
    svd.singular_values = DVector::from_vec(s.into_iter().map(|(v, _idx)| v).collect());
}

fn sorted_svd(mat: DMatrix<f64>) -> SVD<f64, Dynamic, Dynamic> {
    let mut svd = mat.svd(true, true);
    sort_svd(&mut svd);
    return svd;
}

#[wasm_bindgen]
pub fn svd(a_data: &[f64], nrows: usize, ncols: usize) -> SvdResult {
    let a = DMatrix::from_column_slice(nrows, ncols, a_data);
    console::time_with_label("computation of SVD");
    let svd = sorted_svd(a);
    console::time_end_with_label("computation of SVD");
    return SvdResult::new(svd.u.unwrap(), svd.singular_values, svd.v_t.unwrap());
}

// Randomized algorithm that calculates the truncated SVD
// technique based on https://research.fb.com/fast-randomized-svd/
// Precondition: t <= MIN(nrows, ncols)
#[wasm_bindgen]
pub fn svd_simple_approx(a_data: &[f64], nrows: usize, ncols: usize, t: usize) -> SvdResult {
    let a = DMatrix::from_column_slice(nrows, ncols, a_data);

    console::time_with_label("computation of approximate SVD");

    // Generate matrix Ω ∈ ℝ^{m × n}
    let mut rng = SmallRng::seed_from_u64(2342);
    let distr = Uniform::new(-1.0, 1.0);
    let omega: DMatrix<f64> = DMatrix::from_distribution(ncols, t, &distr, &mut rng);

    // Compute Y = A Ω
    let y = (&a) * omega;

    // Compute the QR decomposition of Y, Y = Q R
    let q = y.qr().q();

    // Compute B = Qᵀ A
    let b = q.tr_mul(&a);

    // Compute the SVD of B
    let b_svd = sorted_svd(b);

    let u = q * b_svd.u.unwrap();

    console::time_end_with_label("computation of approximate SVD");

    return SvdResult::new(u, b_svd.singular_values, b_svd.v_t.unwrap());
}
<|endoftext|>


<commit_before>use dces::prelude::Entity;

use crate::{layout::*, render_object::*};

use super::BuildContext;

/// The `Template` trait is used to implement a particular widget type.
///
/// When a widget's `Template` is implemented, it provides three object types:
/// * a template objet (with default values for its properties, children, handlers)
/// * a render object
/// * a layout object
pub trait Template: Sized {
    /// Builds the template of the widget and returns it.
    ///
    /// # Arguments
    /// * `_id`: The id (Entity) of the instantiated widget in the Entity Store
    /// * `_context`: The BuildContext used to build and instantiate new widgets
    ///
    /// # Example
    /// Define a widget called MyWidget with min, max and val properties with
    /// type of usize, and then set default values and add a TextBlock child.
    ///
    /// ```
    /// widget!(MyWidget {
    ///     min: usize,
    ///     max: usize,
    ///     val: usize
    /// });
    ///
    /// impl Template for MyWidget {
    ///     fn template(self, _id: Entity, context: &mut BuildContext) -> Self {
    ///         self.name("MyWidget")
    ///             .min(100)
    ///             .max(1000)
    ///             .val(500)
    ///             .child(TextBlock::new().text("Set a value!").build(context))
    ///     }
    ///
    ///     fn render_object(&self) -> Box<dyn RenderObject> {
    ///         Box::new(RectangleRenderObject)
    ///     }
    ///
    ///     fn layout(&self) -> Box<dyn Layout> {
    ///        Box::new(AbsoluteLayout)
    ///     }
    /// }
    /// ```
    fn template(self, _id: Entity, _ctx: &mut BuildContext) -> Self {
        self
    }

    /// Returns a pointer to a heap allocated object.
    ///
    /// Widgets will be rendered as pixmaps inside the render buffer.
    /// For the list of available render objects, see the
    /// [`render_object`] module.
    ///
    /// [`render_object`]: ../../orbtk_core/render_object/index.html
    fn render_object(&self) -> Box<dyn RenderObject> {
        DefaultRenderObject.into()
    }

    /// Returns a pointer to a heap allocated object.
    ///
    /// The `layout` process will arrange all `box` entities of a widget
=======
    /// The layout process will arrange all `box` entities of a widget
>>>>>>> fa56d7f1 (orbtk_core: update template documentation)
    /// in a tree, were size properties will meet the individual constraints.
    /// For the list of available layout objects, see
    /// the [`layout`] module.
    ///
    /// [`layout`]: ../../orbtk_core/layout/index.html
    fn layout(&self) -> Box<dyn Layout> {
        GridLayout::new().into()
    }
}
<commit_msg>orbtk_core: update template documentation<commit_after>use dces::prelude::Entity;

use crate::{layout::*, render_object::*};

use super::BuildContext;

/// The `Template` trait is used to implement a particular widget type.
///
/// When a widget's `Template` is implemented, it provides three object types:
/// * a template objet (with default values for its properties, children, handlers)
/// * a render object
/// * a layout object
pub trait Template: Sized {
    /// Builds the template of the widget and returns it.
    ///
    /// # Arguments
    /// * `_id`: The id (Entity) of the instantiated widget in the Entity Store
    /// * `_context`: The BuildContext used to build and instantiate new widgets
    ///
    /// # Example
    /// Define a widget called MyWidget with min, max and val properties with
    /// type of usize, and then set default values and add a TextBlock child.
    ///
    /// ```
    /// widget!(MyWidget {
    ///     min: usize,
    ///     max: usize,
    ///     val: usize
    /// });
    ///
    /// impl Template for MyWidget {
    ///     fn template(self, _id: Entity, context: &mut BuildContext) -> Self {
    ///         self.name("MyWidget")
    ///             .min(100)
    ///             .max(1000)
    ///             .val(500)
    ///             .child(TextBlock::new().text("Set a value!").build(context))
    ///     }
    ///
    ///     fn render_object(&self) -> Box<dyn RenderObject> {
    ///         Box::new(RectangleRenderObject)
    ///     }
    ///
    ///     fn layout(&self) -> Box<dyn Layout> {
    ///        Box::new(AbsoluteLayout)
    ///     }
    /// }
    /// ```
    fn template(self, _id: Entity, _ctx: &mut BuildContext) -> Self {
        self
    }

    /// Returns a pointer to a heap allocated object.
    ///
    /// Widgets will be rendered as pixmaps inside the render buffer.
    /// For the list of available render objects, see the
    /// [`render_object`] module.
    ///
    /// [`render_object`]: ../../orbtk_core/render_object/index.html
    fn render_object(&self) -> Box<dyn RenderObject> {
        DefaultRenderObject.into()
    }

    /// Returns a pointer to a heap allocated object.
    ///
    /// The `layout` process will arrange all `box` entities of a widget
    /// in a tree, were size properties will meet the individual constraints.
    /// For the list of available layout objects, see
    /// the [`layout`] module.
    ///
    /// [`layout`]: ../../orbtk_core/layout/index.html
    fn layout(&self) -> Box<dyn Layout> {
        GridLayout::new().into()
    }
}
<|endoftext|>


<commit_before>extern crate cfg_if;

use cfg_if::cfg_if;

cfg_if! {
    if #[cfg(all(windows, feature = "neon-sys"))] {
        use std::env::var;
        use std::path::Path;

        const NODE_ROOT_DIR: &'static str = include_str!(concat!(env!("OUT_DIR"), "\\node_root_dir"));
        const NODE_ARCH:     &'static str = include_str!(concat!(env!("OUT_DIR"), "\\node_arch"));
        const NODE_LIB_FILE: &'static str = include_str!(concat!(env!("OUT_DIR"), "\\node_lib_file"));

        /// Set up the build environment by setting Cargo configuration variables.
        pub fn setup() {
            let debug = var("DEBUG").ok().map_or(false, |s| s == "true");
            let configuration = if debug { "Debug" } else { "Release" };
            let node_lib_file_path = Path::new(NODE_LIB_FILE);
            let mut node_lib_path = Path::new(NODE_ROOT_DIR).to_path_buf();
            node_lib_path.push(NODE_ARCH);
            println!("cargo:rustc-link-search={}\\{}", NODE_ROOT_DIR, configuration);
            println!("cargo:rustc-link-search=native={}", &node_lib_path.display());
            println!("cargo:rustc-link-lib={}", &node_lib_file_path.file_stem().unwrap().to_str().unwrap());

            // Link `win_delay_load_hook.obj` for windows electron
            let node_runtime_env = "npm_config_runtime";
            println!("cargo:rerun-if-env-changed={}", node_runtime_env);
            if var(node_runtime_env).map(|s| s == "electron") == Ok(true) {
                println!("cargo:rustc-cdylib-link-arg=win_delay_load_hook.obj");
                println!("cargo:rustc-cdylib-link-arg=delayimp.lib");
                println!("cargo:rustc-cdylib-link-arg=/DELAYLOAD:node.exe");
            }
        }
    } else if #[cfg(windows)] {
        // ^ automatically not neon-sys
        use std::io::{Error, ErrorKind, Result};
        use std::process::Command;
        use std::path::Path;

        fn node_version() -> Result<String> {
            let output = Command::new("node").arg("-v").output()?;
            if !output.status.success() {
                let hopefully_stack_trace = String::from_utf8(output.stderr)
                    .unwrap_or_else(|_| "<subprocess output garbage>".to_string());
                panic!("Could not download node.lib: {}", hopefully_stack_trace);
            }
            let stdout = String::from_utf8(output.stdout).map_err(|error| {
                Error::new(ErrorKind::InvalidData, error)
            })?;
            Ok(stdout.trim().to_string())
        }

        fn download_node_lib(version: &str, arch: &str) -> Result<Vec<u8>> {
            let script = r#"
                var url = process.argv[1]
                require("https").get(url, function (res) {
                    res.pipe(process.stdout);
                });
            "#;
            let url = format!("https://nodejs.org/dist/{version}/win-{arch}/node.lib", version = version, arch = arch);

            let output = Command::new("node")
                .arg("-e").arg(script)
                .arg(url)
                .output()?;

            Ok(output.stdout)
        }

        /// Set up the build environment by setting Cargo configuration variables.
        pub fn setup() {
            // If the user specified a node.lib path, we do not need to download
            if let Some(node_lib_path) = std::env::var_os("NEON_NODE_LIB") {
                let node_lib_path = Path::new(&node_lib_path);
                // Clearing the file name returns the root+directory name
                let dir = node_lib_path.with_file_name("");
                let basename = node_lib_path.file_stem().expect("Could not parse lib name from NEON_NODE_LIB. Does the path include the full file name?");

                println!("cargo:rustc-link-search=native={}", dir.display());
                // Littul hack to output the OsStr file stem
                println!("cargo:rustc-link-lib={}", Path::new(basename).display());
                return;
            }

            let version = node_version().expect("Could not determine Node.js version");
            let arch = if std::env::var("CARGO_CFG_TARGET_ARCH").unwrap() == "x86" {
                "x86"
            } else {
                "x64"
            };

            let node_lib = download_node_lib(&version, arch).expect("Could not download `node.lib`");
            std::fs::write(format!(r"{}\node-{}.lib", env!("OUT_DIR"), arch), &node_lib).expect("Could not save `node.lib`");

            println!("cargo:rustc-link-search=native={}", env!("OUT_DIR"));
            println!("cargo:rustc-link-lib=node-{}", arch);
        }
    } else if #[cfg(target_os = "macos")] {
        /// Set up the build environment by setting Cargo configuration variables.
        pub fn setup() {
            println!("cargo:rustc-cdylib-link-arg=-undefined");
            println!("cargo:rustc-cdylib-link-arg=dynamic_lookup");
        }
    } else {
        pub fn setup() { }
    }
}
<commit_msg>build: only download node.lib if we dont have one yet<commit_after>extern crate cfg_if;

use cfg_if::cfg_if;

cfg_if! {
    if #[cfg(all(windows, feature = "neon-sys"))] {
        use std::env::var;
        use std::path::Path;

        const NODE_ROOT_DIR: &'static str = include_str!(concat!(env!("OUT_DIR"), "\\node_root_dir"));
        const NODE_ARCH:     &'static str = include_str!(concat!(env!("OUT_DIR"), "\\node_arch"));
        const NODE_LIB_FILE: &'static str = include_str!(concat!(env!("OUT_DIR"), "\\node_lib_file"));

        /// Set up the build environment by setting Cargo configuration variables.
        pub fn setup() {
            let debug = var("DEBUG").ok().map_or(false, |s| s == "true");
            let configuration = if debug { "Debug" } else { "Release" };
            let node_lib_file_path = Path::new(NODE_LIB_FILE);
            let mut node_lib_path = Path::new(NODE_ROOT_DIR).to_path_buf();
            node_lib_path.push(NODE_ARCH);
            println!("cargo:rustc-link-search={}\\{}", NODE_ROOT_DIR, configuration);
            println!("cargo:rustc-link-search=native={}", &node_lib_path.display());
            println!("cargo:rustc-link-lib={}", &node_lib_file_path.file_stem().unwrap().to_str().unwrap());

            // Link `win_delay_load_hook.obj` for windows electron
            let node_runtime_env = "npm_config_runtime";
            println!("cargo:rerun-if-env-changed={}", node_runtime_env);
            if var(node_runtime_env).map(|s| s == "electron") == Ok(true) {
                println!("cargo:rustc-cdylib-link-arg=win_delay_load_hook.obj");
                println!("cargo:rustc-cdylib-link-arg=delayimp.lib");
                println!("cargo:rustc-cdylib-link-arg=/DELAYLOAD:node.exe");
            }
        }
    } else if #[cfg(windows)] {
        // ^ automatically not neon-sys
        use std::io::{Error, ErrorKind, Result};
        use std::process::Command;
        use std::path::Path;

        fn node_version() -> Result<String> {
            let output = Command::new("node").arg("-v").output()?;
            if !output.status.success() {
                let hopefully_stack_trace = String::from_utf8(output.stderr)
                    .unwrap_or_else(|_| "<subprocess output garbage>".to_string());
                panic!("Could not download node.lib: {}", hopefully_stack_trace);
            }
            let stdout = String::from_utf8(output.stdout).map_err(|error| {
                Error::new(ErrorKind::InvalidData, error)
            })?;
            Ok(stdout.trim().to_string())
        }

        fn download_node_lib(version: &str, arch: &str) -> Result<Vec<u8>> {
            let script = r#"
                var url = process.argv[1]
                require("https").get(url, function (res) {
                    res.pipe(process.stdout);
                });
            "#;
            let url = format!("https://nodejs.org/dist/{version}/win-{arch}/node.lib", version = version, arch = arch);

            let output = Command::new("node")
                .arg("-e").arg(script)
                .arg(url)
                .output()?;

            Ok(output.stdout)
        }

        /// Set up the build environment by setting Cargo configuration variables.
        pub fn setup() {
            // If the user specified a node.lib path, we do not need to download
            if let Some(node_lib_path) = std::env::var_os("NEON_NODE_LIB") {
                let node_lib_path = Path::new(&node_lib_path);
                // Clearing the file name returns the root+directory name
                let dir = node_lib_path.with_file_name("");
                let basename = node_lib_path.file_stem().expect("Could not parse lib name from NEON_NODE_LIB. Does the path include the full file name?");

                println!("cargo:rustc-link-search=native={}", dir.display());
                // Littul hack to output the OsStr file stem
                println!("cargo:rustc-link-lib={}", Path::new(basename).display());
                return;
            }

            let version = node_version().expect("Could not determine Node.js version");
            let arch = if std::env::var("CARGO_CFG_TARGET_ARCH").unwrap() == "x86" {
                "x86"
            } else {
                "x64"
            };

            let node_lib_store_path = format!(r"{}/node-{}.lib", env!("OUT_DIR"), arch);

            // Download node.lib if it does not exist
            if let Err(_) = std::fs::metadata(&node_lib_store_path) {
                let node_lib = download_node_lib(&version, arch).expect("Could not download `node.lib`");
                std::fs::write(&node_lib_store_path, &node_lib).expect("Could not save `node.lib`");
            }

            println!("cargo:rustc-link-search=native={}", env!("OUT_DIR"));
            println!("cargo:rustc-link-lib=node-{}", arch);
        }
    } else if #[cfg(target_os = "macos")] {
        /// Set up the build environment by setting Cargo configuration variables.
        pub fn setup() {
            println!("cargo:rustc-cdylib-link-arg=-undefined");
            println!("cargo:rustc-cdylib-link-arg=dynamic_lookup");
        }
    } else {
        pub fn setup() { }
    }
}
<|endoftext|>