<commit_before>extern crate pkg_config;
use std::process::Command;
use std::path::PathBuf;
use std::env;
use std::fs;

fn lib_available(name: &str) -> bool {
    match pkg_config::find_library(name) {
        Ok(_) => true,
        Err(_) => {
            let res = Command::new("ldconfig").arg("--print-cache").output().unwrap();
            if res.status.success() {
                String::from_utf8(res.stdout).unwrap().contains(name)
            } else {
                false
            }
        }
    }
}

fn windows(_: String) {
    // TODO: Use precompiled binary!
    unimplemented!();
}

fn osx(_: String) {
    // TODO: I down't own any apple hardware to test this.
    unimplemented!();
}

fn linux(target: String) {
    if !lib_available("soundio") {
        build(target);
    } else {
        // TODO: remove else branch
        build(target);
    }
}

fn main() {
    let target = env::var("TARGET").unwrap();
    if target.contains("windows") {
        windows(target)
    } else if target.contains("apple") {
        osx(target)
    } else {
        // assume the rest is linux
        linux(target)
    }
}

const LIBSOUNDIO_TAR: &'static str = "http://libsound.io/release/libsoundio-1.1.0.tar.gz";
const LIBSOUNDIO_WIN: &'static str = "http://libsound.io/release/libsoundio-1.1.0.zip";

fn build(target: String) {
    let host = env::var("HOST").unwrap();
    let dst_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
    let dst_root = format!("{}", &dst_dir.display());

    // set cargo flags
    println!("cargo:rustc-link-search={}/lib", &dst_root);
    println!("cargo:rustc-link-lib=static={}", "soundio");
    println!("cargo:include={}/include", &dst_root);
    println!("cargo:root={}", &dst_root);

    // download and extract libsoundio source
    Command::new("curl")
        .current_dir(&dst_dir)
        .args(&["--location", "--remote-name"])
        .arg(LIBSOUNDIO_TAR)
        .output()
        .unwrap();
    Command::new("tar")
        .current_dir(&dst_dir)
        .arg("-xvzf")
        .arg("libsoundio-1.1.0.tar.gz")
        .output()
        .unwrap();

    // create build dir
    let soundio_root = dst_dir.join("libsoundio-1.1.0");
    let build_dir = soundio_root.join("build");
    fs::create_dir(&build_dir).unwrap();

    // run cmake
    Command::new("cmake")
        .current_dir(&build_dir)
        .env("CMAKE_BUILD_TYPE", "Release")
        .env("CMAKE_INSTALL_LIBDIR", "lib")
        .env("CMAKE_INSTALL_PREFIX", format!("{}", &dst_root))
        .env("BUILD_EXAMPLE_PROGRAMS", "OFF")
        .env("BUILD_TESTS", "OFF")
        .env("BUILD_STATIC_LIBS", "ON")
        .env("ENABLE_JACK", "OFF")
        .arg("..")
        .output()
        .unwrap();

    // make install
    Command::new("make")
        .current_dir(&build_dir)
        .arg("install")
        .output()
        .unwrap();

    // remove builddir
    fs::remove_dir_all(build_dir).unwrap();
}
<commit_msg>Fix cmake call specifying envs as `-DENV=VAL` arguments<commit_after>extern crate pkg_config;
use std::process::Command;
use std::path::PathBuf;
use std::env;
use std::fs;

fn lib_available(name: &str) -> bool {
    match pkg_config::find_library(name) {
        Ok(_) => true,
        Err(_) => {
            let res = Command::new("ldconfig").arg("--print-cache").output().unwrap();
            if res.status.success() {
                String::from_utf8(res.stdout).unwrap().contains(name)
            } else {
                false
            }
        }
    }
}

fn windows(_: String) {
    // TODO: Use precompiled binary!
    unimplemented!();
}

fn osx(_: String) {
    // TODO: I down't own any apple hardware to test this.
    unimplemented!();
}

fn linux(target: String) {
    if !lib_available("soundio") {
        build(target);
    } else {
        // TODO: remove else branch
        build(target);
    }
}

fn main() {
    let target = env::var("TARGET").unwrap();
    if target.contains("windows") {
        windows(target)
    } else if target.contains("apple") {
        osx(target)
    } else {
        // assume the rest is linux
        linux(target)
    }
}

const LIBSOUNDIO_TAR: &'static str = "http://libsound.io/release/libsoundio-1.1.0.tar.gz";
const LIBSOUNDIO_WIN: &'static str = "http://libsound.io/release/libsoundio-1.1.0.zip";

fn build(target: String) {
    let host = env::var("HOST").unwrap();
    let dst_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
    let dst_root = format!("{}", &dst_dir.display());

    // set cargo flags
    println!("cargo:rustc-link-search={}/lib", &dst_root);
    println!("cargo:rustc-link-lib=static={}", "soundio");
    println!("cargo:include={}/include", &dst_root);
    println!("cargo:root={}", &dst_root);

    // download and extract libsoundio source
    Command::new("curl")
        .current_dir(&dst_dir)
        .args(&["--location", "--remote-name"])
        .arg(LIBSOUNDIO_TAR)
        .output()
        .unwrap();
    Command::new("tar")
        .current_dir(&dst_dir)
        .arg("-xvzf")
        .arg("libsoundio-1.1.0.tar.gz")
        .output()
        .unwrap();

    // create build dir
    let soundio_root = dst_dir.join("libsoundio-1.1.0");
    let build_dir = soundio_root.join("build");
    fs::create_dir(&build_dir).unwrap();

    // run cmake
    Command::new("cmake")
        .current_dir(&build_dir)
        .arg("-DCMAKE_BUILD_TYPE=Debug")
        .arg("-DCMAKE_INSTALL_LIBDIR:PATH=lib")
        .arg(format!("-DCMAKE_INSTALL_PREFIX:PATH={}", &dst_dir.display()))
        .arg("-DBUILD_EXAMPLE_PROGRAMS:BOOL=OFF")
        .arg("-DBUILD_TESTS:BOOL=OFF")
        .arg("-DBUILD_STATIC_LIBS:BOOL=OFF")
        .arg("-DBUILD_SHARED_LIBS:BOOL=ON")
        .arg("-DENABLE_JACK:BOOL=OFF")
        .arg("-DENABLE_PULSEAUDIO:BOOL=OFF")
        .arg("-DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON")
        .arg("..")
        .output()
        .unwrap();

    // make install
    Command::new("make")
        .current_dir(&build_dir)
        .arg("install")
        .output()
        .unwrap();

    // remove builddir
    fs::remove_dir_all(build_dir).unwrap();
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

#![allow(clippy::print_literal)]
#![allow(clippy::unused_io_amount)]

use rustc_version::{version, Version};
#[allow(unused_imports)]
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::exit;

#[allow(dead_code)]
fn rerun_dir<P: AsRef<Path>>(dir: P) {
  for entry in fs::read_dir(dir).unwrap() {
    let entry = entry.unwrap();
    let path = entry.path();
    println!("cargo:rerun-if-changed={}", path.to_string_lossy());

    if path.is_dir() {
      rerun_dir(path);
    }
  }
}

#[allow(dead_code)]
fn hash_changed(
  files: &[&str], out_dir: &str, config: &Path,
) -> Option<([u8; 8], PathBuf)> {
  use std::collections::hash_map::DefaultHasher;
  use std::hash::Hasher;
  use std::io::Read;

  let mut hasher = DefaultHasher::new();

  let paths = files.iter().map(Path::new).chain(std::iter::once(config));

  for path in paths {
    if let Ok(mut f) = std::fs::File::open(path) {
      let mut buf = Vec::new();
      f.read_to_end(&mut buf).unwrap();

      hasher.write(&buf);
    } else {
      panic!("Cannot open {}", path.display());
    }
  }

  let hash = hasher.finish().to_be_bytes();

  let hash_path = Path::new(&out_dir).join("asm.hash");

  if let Ok(old_hash) = std::fs::read(&hash_path) {
    if old_hash == hash {
      return None;
    }
  }

  Some((hash, hash_path))
}

#[cfg(feature = "asm")]
fn build_nasm_files() {
  use std::fs::File;
  use std::io::Write;
  let out_dir = env::var("OUT_DIR").unwrap();

  let dest_path = Path::new(&out_dir).join("config.asm");
  let mut config_file = File::create(&dest_path).unwrap();
  config_file.write(b"	%define private_prefix rav1e\n").unwrap();
  config_file.write(b"	%define ARCH_X86_32 0\n").unwrap();
  config_file.write(b" %define ARCH_X86_64 1\n").unwrap();
  config_file.write(b"	%define PIC 1\n").unwrap();
  config_file.write(b" %define STACK_ALIGNMENT 16\n").unwrap();
  if cfg!(target_os = "macos") {
    config_file.write(b" %define PREFIX 1\n").unwrap();
  }

  let asm_files = &[
    "src/x86/ipred.asm",
    "src/x86/ipred_ssse3.asm",
    "src/x86/itx.asm",
    "src/x86/itx_ssse3.asm",
    "src/x86/mc.asm",
    "src/x86/mc_ssse3.asm",
    "src/x86/me.asm",
    "src/x86/sad_sse2.asm",
    "src/x86/sad_avx.asm",
    "src/x86/satd.asm",
    "src/x86/cdef.asm",
    "src/x86/tables.asm",
  ];

  if let Some((hash, hash_path)) =
    hash_changed(asm_files, &out_dir, &dest_path)
  {
    let mut config_include_arg = String::from("-I");
    config_include_arg.push_str(&out_dir);
    config_include_arg.push('/');
    nasm_rs::compile_library_args(
      "rav1easm",
      asm_files,
      &[&config_include_arg, "-Isrc/"],
    );
    std::fs::write(hash_path, &hash[..]).unwrap();
  } else {
    println!("cargo:rustc-link-search={}", out_dir);
  }
  println!("cargo:rustc-link-lib=static=rav1easm");
  rerun_dir("src/x86");
  rerun_dir("src/ext/x86");
}

#[cfg(feature = "asm")]
fn build_asm_files() {
  use std::fs::File;
  use std::io::Write;
  let out_dir = env::var("OUT_DIR").unwrap();

  let dest_path = Path::new(&out_dir).join("config.h");
  let mut config_file = File::create(&dest_path).unwrap();
  config_file.write(b" #define PRIVATE_PREFIX rav1e_\n").unwrap();
  config_file.write(b" #define ARCH_AARCH64 1\n").unwrap();
  config_file.write(b" #define ARCH_ARM 0\n").unwrap();
  config_file.write(b" #define CONFIG_LOG 1 \n").unwrap();
  config_file.write(b" #define HAVE_ASM 1\n").unwrap();
  config_file.sync_all().unwrap();

  let asm_files = &[
    "src/arm/64/mc.S",
    "src/arm/64/itx.S",
    "src/arm/64/ipred.S",
    "src/arm/64/sad.S",
    "src/arm/tables.S",
  ];

  if let Some((hash, hash_path)) =
    hash_changed(asm_files, &out_dir, &dest_path)
  {
    cc::Build::new()
      .files(asm_files)
      .include(".")
      .include(&out_dir)
      .compile("rav1e-aarch64");

    std::fs::write(hash_path, &hash[..]).unwrap();
  } else {
    println!("cargo:rustc-link-search={}", out_dir);
    println!("cargo:rustc-link-lib=static=rav1e-aarch64");
  }
  rerun_dir("src/arm");
}

fn rustc_version_check() {
  // This should match the version in .travis.yml
  const REQUIRED_VERSION: &str = "1.36.0";
  if version().unwrap() < Version::parse(REQUIRED_VERSION).unwrap() {
    eprintln!("rav1e requires rustc >= {}.", REQUIRED_VERSION);
    exit(1);
  }
}

#[cfg(feature = "asm")]
fn is_nasm_new_enough(
  min_version: Option<(u8, u8, u8)>, nasm_path: &Path,
) -> Result<(), String> {
  match get_output(std::process::Command::new(nasm_path).arg("-v")) {
    Ok(version) => {
      if version.contains("NASM version 0.") {
        Err(version)
      } else if let Some((major, minor, micro)) = min_version {
        let ver = parse_nasm_version(&version)?;
        eprintln!("{:?} {:?} {:?}", min_version, version, ver);
        if major > ver.0
          || (major == ver.0 && minor > ver.1)
          || (major == ver.0 && minor == ver.1 && micro > ver.2)
        {
          Err(version)
        } else {
          Ok(())
        }
      } else {
        Ok(())
      }
    }
    Err(err) => Err(err),
  }
}

#[cfg(feature = "asm")]
fn parse_nasm_version(version_string: &str) -> Result<(u8, u8, u8), String> {
  // Rust regex lib doesn't support empty expressions in alterations,
  // so workaround the other way
  let regex1 =
    regex::Regex::new(r"(?:NASM version )?(\d+)\.(\d+)\.(\d+)").unwrap();
  if let Some(captures) = regex1.captures(version_string) {
    Ok((
      captures[1].parse().expect("Invalid version component"),
      captures[2].parse().expect("Invalid version component"),
      captures[3].parse().expect("Invalid version component"),
    ))
  } else {
    let regex2 = regex::Regex::new(r"(?:NASM version )?(\d+)\.(\d+)").unwrap();
    let captures = regex2
      .captures(version_string)
      .ok_or_else(|| "Unable to parse NASM version string".to_string())?;
    Ok((
      captures[1].parse().expect("Invalid version component"),
      captures[2].parse().expect("Invalid version component"),
      0,
    ))
  }
}

#[test]
fn test_parse_nasm_version() {
  let ver_str = "NASM version 2.14.02 compiled on Jan 22 2019";
  assert_eq!((2, 14, 2), parse_nasm_version(ver_str));
  let ver_str = "NASM version 2.14 compiled on Jan 22 2019";
  assert_eq!((2, 14, 0), parse_nasm_version(ver_str));
}

#[cfg(feature = "asm")]
fn nasm_version_check() -> std::path::PathBuf {
  let nasm_path = std::path::PathBuf::from("nasm");
  match is_nasm_new_enough(Some((2, 14, 0)), &nasm_path) {
    Ok(_) => nasm_path,
    Err(version) => {
      panic!("This version of NASM is too old: {}", version);
    }
  }
}

#[cfg(feature = "asm")]
fn get_output(cmd: &mut std::process::Command) -> Result<String, String> {
  let out = cmd.output().map_err(|e| e.to_string())?;
  if out.status.success() {
    Ok(String::from_utf8_lossy(&out.stdout).to_string())
  } else {
    Err(String::from_utf8_lossy(&out.stderr).to_string())
  }
}

#[allow(unused_variables)]
fn main() {
  rustc_version_check();

  let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
  let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
  // let env = env::var("CARGO_CFG_TARGET_ENV").unwrap();

  #[cfg(feature = "asm")]
  {
    if arch == "x86_64" {
      println!("cargo:rustc-cfg={}", "nasm_x86_64");
      nasm_version_check();
      build_nasm_files()
    }
    if arch == "aarch64" {
      println!("cargo:rustc-cfg={}", "asm_neon");
      build_asm_files()
    }
  }

  if os == "windows" && cfg!(feature = "decode_test") {
    panic!("Unsupported feature on this platform!");
  }

  vergen::generate_cargo_keys(vergen::ConstantsFlags::all())
    .expect("Unable to generate the cargo keys!");

  println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
}
<commit_msg>Define HAVE_AVX512ICL symbol<commit_after>// Copyright (c) 2017-2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

#![allow(clippy::print_literal)]
#![allow(clippy::unused_io_amount)]

use rustc_version::{version, Version};
#[allow(unused_imports)]
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::exit;

#[allow(dead_code)]
fn rerun_dir<P: AsRef<Path>>(dir: P) {
  for entry in fs::read_dir(dir).unwrap() {
    let entry = entry.unwrap();
    let path = entry.path();
    println!("cargo:rerun-if-changed={}", path.to_string_lossy());

    if path.is_dir() {
      rerun_dir(path);
    }
  }
}

#[allow(dead_code)]
fn hash_changed(
  files: &[&str], out_dir: &str, config: &Path,
) -> Option<([u8; 8], PathBuf)> {
  use std::collections::hash_map::DefaultHasher;
  use std::hash::Hasher;
  use std::io::Read;

  let mut hasher = DefaultHasher::new();

  let paths = files.iter().map(Path::new).chain(std::iter::once(config));

  for path in paths {
    if let Ok(mut f) = std::fs::File::open(path) {
      let mut buf = Vec::new();
      f.read_to_end(&mut buf).unwrap();

      hasher.write(&buf);
    } else {
      panic!("Cannot open {}", path.display());
    }
  }

  let hash = hasher.finish().to_be_bytes();

  let hash_path = Path::new(&out_dir).join("asm.hash");

  if let Ok(old_hash) = std::fs::read(&hash_path) {
    if old_hash == hash {
      return None;
    }
  }

  Some((hash, hash_path))
}

#[cfg(feature = "asm")]
fn build_nasm_files() {
  use std::fs::File;
  use std::io::Write;
  let out_dir = env::var("OUT_DIR").unwrap();

  let dest_path = Path::new(&out_dir).join("config.asm");
  let mut config_file = File::create(&dest_path).unwrap();
  config_file.write(b"	%define private_prefix rav1e\n").unwrap();
  config_file.write(b"	%define ARCH_X86_32 0\n").unwrap();
  config_file.write(b" %define ARCH_X86_64 1\n").unwrap();
  config_file.write(b"	%define PIC 1\n").unwrap();
  config_file.write(b" %define STACK_ALIGNMENT 16\n").unwrap();
  config_file.write(b" %define HAVE_AVX512ICL 0\n").unwrap();
  if cfg!(target_os = "macos") {
    config_file.write(b" %define PREFIX 1\n").unwrap();
  }

  let asm_files = &[
    "src/x86/ipred.asm",
    "src/x86/ipred_ssse3.asm",
    "src/x86/itx.asm",
    "src/x86/itx_ssse3.asm",
    "src/x86/mc.asm",
    "src/x86/mc_ssse3.asm",
    "src/x86/me.asm",
    "src/x86/sad_sse2.asm",
    "src/x86/sad_avx.asm",
    "src/x86/satd.asm",
    "src/x86/cdef.asm",
    "src/x86/tables.asm",
  ];

  if let Some((hash, hash_path)) =
    hash_changed(asm_files, &out_dir, &dest_path)
  {
    let mut config_include_arg = String::from("-I");
    config_include_arg.push_str(&out_dir);
    config_include_arg.push('/');
    nasm_rs::compile_library_args(
      "rav1easm",
      asm_files,
      &[&config_include_arg, "-Isrc/"],
    );
    std::fs::write(hash_path, &hash[..]).unwrap();
  } else {
    println!("cargo:rustc-link-search={}", out_dir);
  }
  println!("cargo:rustc-link-lib=static=rav1easm");
  rerun_dir("src/x86");
  rerun_dir("src/ext/x86");
}

#[cfg(feature = "asm")]
fn build_asm_files() {
  use std::fs::File;
  use std::io::Write;
  let out_dir = env::var("OUT_DIR").unwrap();

  let dest_path = Path::new(&out_dir).join("config.h");
  let mut config_file = File::create(&dest_path).unwrap();
  config_file.write(b" #define PRIVATE_PREFIX rav1e_\n").unwrap();
  config_file.write(b" #define ARCH_AARCH64 1\n").unwrap();
  config_file.write(b" #define ARCH_ARM 0\n").unwrap();
  config_file.write(b" #define CONFIG_LOG 1 \n").unwrap();
  config_file.write(b" #define HAVE_ASM 1\n").unwrap();
  config_file.sync_all().unwrap();

  let asm_files = &[
    "src/arm/64/mc.S",
    "src/arm/64/itx.S",
    "src/arm/64/ipred.S",
    "src/arm/64/sad.S",
    "src/arm/tables.S",
  ];

  if let Some((hash, hash_path)) =
    hash_changed(asm_files, &out_dir, &dest_path)
  {
    cc::Build::new()
      .files(asm_files)
      .include(".")
      .include(&out_dir)
      .compile("rav1e-aarch64");

    std::fs::write(hash_path, &hash[..]).unwrap();
  } else {
    println!("cargo:rustc-link-search={}", out_dir);
    println!("cargo:rustc-link-lib=static=rav1e-aarch64");
  }
  rerun_dir("src/arm");
}

fn rustc_version_check() {
  // This should match the version in .travis.yml
  const REQUIRED_VERSION: &str = "1.36.0";
  if version().unwrap() < Version::parse(REQUIRED_VERSION).unwrap() {
    eprintln!("rav1e requires rustc >= {}.", REQUIRED_VERSION);
    exit(1);
  }
}

#[cfg(feature = "asm")]
fn is_nasm_new_enough(
  min_version: Option<(u8, u8, u8)>, nasm_path: &Path,
) -> Result<(), String> {
  match get_output(std::process::Command::new(nasm_path).arg("-v")) {
    Ok(version) => {
      if version.contains("NASM version 0.") {
        Err(version)
      } else if let Some((major, minor, micro)) = min_version {
        let ver = parse_nasm_version(&version)?;
        eprintln!("{:?} {:?} {:?}", min_version, version, ver);
        if major > ver.0
          || (major == ver.0 && minor > ver.1)
          || (major == ver.0 && minor == ver.1 && micro > ver.2)
        {
          Err(version)
        } else {
          Ok(())
        }
      } else {
        Ok(())
      }
    }
    Err(err) => Err(err),
  }
}

#[cfg(feature = "asm")]
fn parse_nasm_version(version_string: &str) -> Result<(u8, u8, u8), String> {
  // Rust regex lib doesn't support empty expressions in alterations,
  // so workaround the other way
  let regex1 =
    regex::Regex::new(r"(?:NASM version )?(\d+)\.(\d+)\.(\d+)").unwrap();
  if let Some(captures) = regex1.captures(version_string) {
    Ok((
      captures[1].parse().expect("Invalid version component"),
      captures[2].parse().expect("Invalid version component"),
      captures[3].parse().expect("Invalid version component"),
    ))
  } else {
    let regex2 = regex::Regex::new(r"(?:NASM version )?(\d+)\.(\d+)").unwrap();
    let captures = regex2
      .captures(version_string)
      .ok_or_else(|| "Unable to parse NASM version string".to_string())?;
    Ok((
      captures[1].parse().expect("Invalid version component"),
      captures[2].parse().expect("Invalid version component"),
      0,
    ))
  }
}

#[test]
fn test_parse_nasm_version() {
  let ver_str = "NASM version 2.14.02 compiled on Jan 22 2019";
  assert_eq!((2, 14, 2), parse_nasm_version(ver_str));
  let ver_str = "NASM version 2.14 compiled on Jan 22 2019";
  assert_eq!((2, 14, 0), parse_nasm_version(ver_str));
}

#[cfg(feature = "asm")]
fn nasm_version_check() -> std::path::PathBuf {
  let nasm_path = std::path::PathBuf::from("nasm");
  match is_nasm_new_enough(Some((2, 14, 0)), &nasm_path) {
    Ok(_) => nasm_path,
    Err(version) => {
      panic!("This version of NASM is too old: {}", version);
    }
  }
}

#[cfg(feature = "asm")]
fn get_output(cmd: &mut std::process::Command) -> Result<String, String> {
  let out = cmd.output().map_err(|e| e.to_string())?;
  if out.status.success() {
    Ok(String::from_utf8_lossy(&out.stdout).to_string())
  } else {
    Err(String::from_utf8_lossy(&out.stderr).to_string())
  }
}

#[allow(unused_variables)]
fn main() {
  rustc_version_check();

  let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
  let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
  // let env = env::var("CARGO_CFG_TARGET_ENV").unwrap();

  #[cfg(feature = "asm")]
  {
    if arch == "x86_64" {
      println!("cargo:rustc-cfg={}", "nasm_x86_64");
      nasm_version_check();
      build_nasm_files()
    }
    if arch == "aarch64" {
      println!("cargo:rustc-cfg={}", "asm_neon");
      build_asm_files()
    }
  }

  if os == "windows" && cfg!(feature = "decode_test") {
    panic!("Unsupported feature on this platform!");
  }

  vergen::generate_cargo_keys(vergen::ConstantsFlags::all())
    .expect("Unable to generate the cargo keys!");

  println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
}
<|endoftext|>


<commit_before>//! An rope.
//!
//! A rope is an efficient data structure for large mutable strings. It's
//! essentially a binary tree whose leaves are strings.
//!
//! For more information, see the following resources:
//! + http://scienceblogs.com/goodmath/2009/01/26/ropes-twining-together-strings/
//! + https://www.ibm.com/developerworks/library/j-ropes/
//! + http://citeseer.ist.psu.edu/viewdoc/download?doi=10.1.1.14.9450&rep=rep1&type=pdf

use std::ops;

#[derive(Debug)]
pub struct Rope{
    // can we get away with having these be of &str or will they need
    // to be string?
    root: Node
}

#[derive(Debug)]
enum Node { /// A leaf node
            // todo: is box<str> the right choice?
            Leaf(Box<str>)
          , /// A branch node
            Branch { l: Box<Node>, r: Box<Node> }
          , /// Nothing
            None
}

impl ops::Add for Rope {
    type Output = Rope;

    // This is the concat operation.
    fn add(self, other: Rope) -> Rope {
        unimplemented!()
    }
}

impl ops::Index<usize> for Rope {
    type Output = char;

    // Index a character
    fn index(&self, i: usize) -> &char {
        unimplemented!()
    }
}

// slicing operators -----------------------------------------
impl ops::Index<ops::Range<usize>> for Rope {
    type Output = str;

    // Index a substring
    fn index(&self, i: ops::Range<usize>) -> &str {
        unimplemented!()
    }
}

impl ops::Index<ops::RangeTo<usize>> for Rope {
    type Output = str;

    fn index(&self, i: ops::RangeTo<usize>) -> &str {
        unimplemented!()
    }
}

impl ops::Index<ops::RangeFrom<usize>> for Rope {
    type Output = str;

    fn index(&self, i: ops::RangeFrom<usize>) -> &str {
        unimplemented!()
    }
}

impl ops::IndexMut<ops::Range<usize>> for Rope {
    fn index_mut(&mut self, i: ops::Range<usize>) -> &mut str {
        unimplemented!()
    }
}

impl ops::IndexMut<ops::RangeTo<usize>> for Rope {
    fn index_mut(&mut self, i: ops::RangeTo<usize>) -> &mut str {
        unimplemented!()
    }
}

impl ops::IndexMut<ops::RangeFrom<usize>> for Rope {
    fn index_mut(&mut self, i: ops::RangeFrom<usize>) -> &mut str {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>rope: added some failing tests<commit_after>//! An rope.
//!
//! A rope is an efficient data structure for large mutable strings. It's
//! essentially a binary tree whose leaves are strings.
//!
//! For more information, see the following resources:
//! + http://scienceblogs.com/goodmath/2009/01/26/ropes-twining-together-strings/
//! + https://www.ibm.com/developerworks/library/j-ropes/
//! + http://citeseer.ist.psu.edu/viewdoc/download?doi=10.1.1.14.9450&rep=rep1&type=pdf

#![feature(const_fn)]

use std::ops;
use std::convert;

#[derive(Debug)]
pub struct Rope {
    // can we get away with having these be of &str or will they need
    // to be string?
    root: Node
}

impl Rope {

    /// Returns a new empty Rope
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::new();
    /// assert_eq!(an_rope.length(), 0);
    /// ```
    pub const fn new() -> Rope {
        Rope { root: Node::None }
    }

    /// Returns the length of this Rope
    ///
    /// # Examples
    /// ```
    /// use an_rope::Rope;
    /// let mut an_empty_rope = Rope::new();
    /// assert_eq!(an_empty_rope.length(), 0);
    /// ```
    /// ```
    /// use an_rope::Rope;
    /// let mut an_empty_rope = Rope::from(String::from(""));
    /// assert_eq!(an_empty_rope.length(), 0);
    /// ```
    /// ```
    /// use an_rope::Rope;
    /// let mut an_rope = Rope::from(String::from("a string"));
    /// assert_eq!(an_rope.length(), "a string".len());
    /// ```
    pub fn length(&self) -> usize {
        unimplemented!()
    }
}

#[derive(Debug)]
enum Node { /// A leaf node
            // todo: is box<str> the right choice?
            Leaf(Box<str>)
          , /// A branch node
            Branch { l: Box<Node>, r: Box<Node> }
          , /// Nothing
            None
}

impl Node {

    /// Computes the weight of a node
    fn weight(&self) -> usize {
        unimplemented!()
    }
}

impl convert::From<String> for Rope {
    fn from(string: String) -> Rope {
        unimplemented!()
    }
}

impl ops::Add for Rope {
    type Output = Rope;

    // This is the concat operation.
    fn add(self, other: Rope) -> Rope {
        unimplemented!()
    }
}

impl ops::Index<usize> for Rope {
    type Output = char;

    // Index a character
    fn index(&self, i: usize) -> &char {
        unimplemented!()
    }
}

// slicing operators -----------------------------------------
impl ops::Index<ops::Range<usize>> for Rope {
    type Output = str;

    // Index a substring
    fn index(&self, i: ops::Range<usize>) -> &str {
        unimplemented!()
    }
}

impl ops::Index<ops::RangeTo<usize>> for Rope {
    type Output = str;

    fn index(&self, i: ops::RangeTo<usize>) -> &str {
        unimplemented!()
    }
}

impl ops::Index<ops::RangeFrom<usize>> for Rope {
    type Output = str;

    fn index(&self, i: ops::RangeFrom<usize>) -> &str {
        unimplemented!()
    }
}

impl ops::IndexMut<ops::Range<usize>> for Rope {
    fn index_mut(&mut self, i: ops::Range<usize>) -> &mut str {
        unimplemented!()
    }
}

impl ops::IndexMut<ops::RangeTo<usize>> for Rope {
    fn index_mut(&mut self, i: ops::RangeTo<usize>) -> &mut str {
        unimplemented!()
    }
}

impl ops::IndexMut<ops::RangeFrom<usize>> for Rope {
    fn index_mut(&mut self, i: ops::RangeFrom<usize>) -> &mut str {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<|endoftext|>


<commit_before>/// OData query parameters
///
/// ## Example
///
/// ```rust
/// use shapir::odata::Parameters;
///
///	let opts = Parameters::new()
///		.select(vec!["Field1", "Field2", "3"])
///		.expand(vec!["Children", "Siblings"])
///		.filter(vec!["A eq B", "true"])
///		.order_by(vec!["Date asc", "Time desc", "Id"])
///		.top(10u32)
///		.skip(9u32);
/// ```
///

#[derive(Debug, Clone, Default)]
pub struct Parameters {
	custom: Option<Vec<(&'static str, String)>>,
	select: Option<Vec<String>>,
	expand: Option<Vec<String>>,
	filter: Option<Vec<String>>,
	order_by: Option<Vec<String>>,
	top: Option<u32>,
	skip: Option<u32>,
}

impl Parameters {
	/// Create a new instance of `Parameters` with no options specified.
	pub fn new() -> Self {
		Parameters {
			custom: None,
			select: None,
			expand: None,
			filter: None,
			order_by: None,
			top: None,
			skip: None,
		}
	}

	/// Set custom parameters
	pub fn custom<V>(mut self, opt: Vec<(&'static str, V)>) -> Self where V: Into<String> {
		let items = opt.into_iter()
			.map(|v| (v.0, v.1.into()))
			.collect();
		self.custom = Some(items);
		self
	}

	/// Add custom parameters
	pub fn custom_add<V>(mut self, param: (&'static str, V)) -> Self where V: Into<String> {
		match self.custom {
			Some(ref mut items) => {
				items.push((param.0, param.1.into()));
			},
			None => {
				self.custom = Some(vec![(param.0, param.1.into())]);
			}
		};

		self
	}

	/// Set `$select` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#theselectsystemqueryoption)
	/// for more details.
	pub fn select<T>(mut self, opt: T) -> Self where T: IntoIterator, T::Item: Into<String> {
		let items = opt.into_iter()
			.map(|v| v.into())
			.collect();
		self.select = Some(items);
		self
	}

	/// Set `$expand` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#theexpandsystemqueryoption)
	/// for more details.
	pub fn expand<T>(mut self, opt: T) -> Self where T: IntoIterator, T::Item: Into<String> {
		let items = opt.into_iter()
			.map(|v| v.into())
			.collect();
		self.expand = Some(items);
		self
	}

	/// Set `$filter` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#thefiltersystemqueryoption)
	/// for more details.
	pub fn filter<T>(mut self, opt: T) -> Self where T: IntoIterator, T::Item: Into<String> {
		let items = opt.into_iter()
			.map(|v| v.into())
			.collect();
		self.filter = Some(items);
		self
	}

	/// Set `$orderBy` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#theorderbysystemqueryoption)
	/// for more details.
	pub fn order_by<T>(mut self, opt: T) -> Self where T: IntoIterator, T::Item: Into<String> {
		let items = opt.into_iter()
			.map(|v| v.into())
			.collect();
		self.order_by = Some(items);
		self
	}

	/// Set `$top` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#thetopsystemqueryoption)
	/// for more details.
	pub fn top<T>(mut self, opt: T) -> Self where T: Into<u32> {
		self.top = Some(opt.into());
		self
	}

	/// Set `$skip` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#theskipsystemqueryoption)
	/// for more details.
	pub fn skip<T>(mut self, opt: T) -> Self where T: Into<u32> {
		self.skip = Some(opt.into());
		self
	}
}

impl Into<String> for Parameters {
	fn into(self) -> String {
		use url::form_urlencoded;

		// Fill in options
		let mut options: Vec<(&str, String)> = Vec::new();

		if let Some(items) = self.custom {
			options.extend(items);
		};

		if let Some(items) = self.select {
			options.push(("$select", items.into_boxed_slice().join(",")));
		};

		if let Some(items) = self.expand {
			options.push(("$expand", items.into_boxed_slice().join(",")));
		};

		if let Some(items) = self.filter {
			options.push(("$filter", items.into_boxed_slice().join(" and ")));
		};

		if let Some(items) = self.order_by {
			options.push(("$orderBy", items.into_boxed_slice().join(",")));
		};

		if let Some(num) = self.top {
			options.push(("$top", num.to_string()));
		};

		if let Some(num) = self.skip {
			options.push(("$skip", num.to_string()));
		};

		// Convert OData options into URL query
		form_urlencoded::serialize(options)
	}
}

impl ToString for Parameters {
	fn to_string(&self) -> String {
		self.clone().into()
	}
}

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

	fn encode_pairs(v: Vec<(&str, &str)>) -> String {
		use url::form_urlencoded;
		form_urlencoded::serialize(v)
	}

	#[test]
	fn query_options_none() {
		let opts: String = Parameters::new()
			.into();
		assert_eq!(opts, "".to_string());
	}

	#[test]
	fn query_options_custom() {
		let opts: String = Parameters::new()
			.custom(vec![("a", "hello"), ("enable", "true")])
			.custom_add(("price", "20"))
			.into();
		assert_eq!(opts, encode_pairs(vec![("a", "hello"), ("enable", "true"), ("price", "20")]));
	}

	#[test]
	fn query_options_select() {
		let opts: String = Parameters::new()
			.select(vec!["Field1", "Field2", "3"])
			.into();
		assert_eq!(opts, encode_pairs(vec![("$select", "Field1,Field2,3")]));
	}

	#[test]
	fn query_options_expand() {
		let opts: String = Parameters::new()
			.expand(vec!["Children", "Siblings"])
			.into();
		assert_eq!(opts, encode_pairs(vec![("$expand", "Children,Siblings")]));
	}

	#[test]
	fn query_options_filter() {
		let opts: String = Parameters::new()
			.filter(vec!["A eq B", "true"])
			.into();
		assert_eq!(opts, encode_pairs(vec![("$filter", "A eq B and true")]));
	}

	#[test]
	fn query_options_order_by() {
		let opts: String = Parameters::new()
			.order_by(vec!["Date asc", "Time desc", "Id"])
			.into();
		assert_eq!(opts, encode_pairs(vec![("$orderBy", "Date asc,Time desc,Id")]));
	}

	#[test]
	fn query_options_top() {
		let opts: String = Parameters::new()
			.top(10u32)
			.into();
		assert_eq!(opts, encode_pairs(vec![("$top", "10")]));
	}

	#[test]
	fn query_options_skip() {
		let opts: String = Parameters::new()
			.skip(9u32)
			.into();
		assert_eq!(opts, encode_pairs(vec![("$skip", "9")]));
	}

	#[test]
	fn query_options_all() {
		let opts: String = Parameters::new()
			.select(vec!["Field1", "Field2", "3"])
			.expand(vec!["Children", "Siblings"])
			.filter(vec!["A eq B", "true"])
			.order_by(vec!["Date asc", "Time desc", "Id"])
			.top(10u32)
			.skip(9u32)
			.into();

		let should_be = encode_pairs(vec![
				("$select", "Field1,Field2,3"),
				("$expand", "Children,Siblings"),
				("$filter", "A eq B and true"),
				("$orderBy", "Date asc,Time desc,Id"),
				("$top", "10"),
				("$skip", "9")
			]);

		assert_eq!(opts, should_be);
	}
}
<commit_msg>Add more convenient methods<commit_after>/// OData query parameters
///
/// ## Example
///
/// ```rust
/// use shapir::odata::Parameters;
///
///	let opts = Parameters::new()
///		.select(vec!["Field1", "Field2", "3"])
///		.expand(vec!["Children", "Siblings"])
///		.filter(vec!["A eq B", "true"])
///		.order_by(vec!["Date asc", "Time desc", "Id"])
///		.top(10u32)
///		.skip(9u32);
/// ```
///

#[derive(Debug, Clone, Default)]
pub struct Parameters {
	custom: Option<Vec<(&'static str, String)>>,
	select: Option<Vec<String>>,
	expand: Option<Vec<String>>,
	filter: Option<Vec<String>>,
	order_by: Option<Vec<String>>,
	top: Option<u32>,
	skip: Option<u32>,
}

impl Parameters {
	/// Create a new instance of `Parameters` with no options specified.
	pub fn new() -> Self {
		Parameters {
			custom: None,
			select: None,
			expand: None,
			filter: None,
			order_by: None,
			top: None,
			skip: None,
		}
	}

	/// Set custom parameters
	pub fn custom<V>(mut self, opt: Vec<(&'static str, V)>) -> Self where V: Into<String> {
		let items = opt.into_iter()
			.map(|v| (v.0, v.1.into()))
			.collect();
		self.custom = Some(items);
		self
	}

	/// Add custom parameter
	pub fn custom_add<V>(mut self, param: (&'static str, V)) -> Self where V: Into<String> {
		match self.custom {
			Some(ref mut items) => {
				items.push((param.0, param.1.into()));
			},
			None => {
				self.custom = Some(vec![(param.0, param.1.into())]);
			}
		};

		self
	}

	/// Set `$select` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#theselectsystemqueryoption)
	/// for more details.
	pub fn select<T>(mut self, opt: T) -> Self where T: IntoIterator, T::Item: Into<String> {
		let items = opt.into_iter()
			.map(|v| v.into())
			.collect();
		self.select = Some(items);
		self
	}

	/// Add `$select` option
	pub fn select_add<V>(mut self, opt: V) -> Self where V: Into<String> {
		match self.select {
			Some(ref mut items) => {
				items.push(opt.into());
			},
			None => {
				self.select = Some(vec![opt.into()]);
			}
		};

		self
	}

	/// Set `$expand` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#theexpandsystemqueryoption)
	/// for more details.
	pub fn expand<T>(mut self, opt: T) -> Self where T: IntoIterator, T::Item: Into<String> {
		let items = opt.into_iter()
			.map(|v| v.into())
			.collect();
		self.expand = Some(items);
		self
	}

	/// Add `$expand` option
	pub fn expand_add<V>(mut self, opt: V) -> Self where V: Into<String> {
		match self.expand {
			Some(ref mut items) => {
				items.push(opt.into());
			},
			None => {
				self.expand = Some(vec![opt.into()]);
			}
		};

		self
	}

	/// Set `$filter` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#thefiltersystemqueryoption)
	/// for more details.
	pub fn filter<T>(mut self, opt: T) -> Self where T: IntoIterator, T::Item: Into<String> {
		let items = opt.into_iter()
			.map(|v| v.into())
			.collect();
		self.filter = Some(items);
		self
	}

	/// Add `$filter` option
	pub fn filter_add<V>(mut self, opt: V) -> Self where V: Into<String> {
		match self.filter {
			Some(ref mut items) => {
				items.push(opt.into());
			},
			None => {
				self.filter = Some(vec![opt.into()]);
			}
		};

		self
	}

	/// Set `$orderBy` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#theorderbysystemqueryoption)
	/// for more details.
	pub fn order_by<T>(mut self, opt: T) -> Self where T: IntoIterator, T::Item: Into<String> {
		let items = opt.into_iter()
			.map(|v| v.into())
			.collect();
		self.order_by = Some(items);
		self
	}

	/// Add `$orderBy` option
	pub fn order_by_add<V>(mut self, opt: V) -> Self where V: Into<String> {
		match self.order_by {
			Some(ref mut items) => {
				items.push(opt.into());
			},
			None => {
				self.order_by = Some(vec![opt.into()]);
			}
		};

		self
	}

	/// Set `$top` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#thetopsystemqueryoption)
	/// for more details.
	pub fn top<T>(mut self, opt: T) -> Self where T: Into<u32> {
		self.top = Some(opt.into());
		self
	}

	/// Set `$skip` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#theskipsystemqueryoption)
	/// for more details.
	pub fn skip<T>(mut self, opt: T) -> Self where T: Into<u32> {
		self.skip = Some(opt.into());
		self
	}
}

impl Into<String> for Parameters {
	fn into(self) -> String {
		use url::form_urlencoded;

		// Fill in options
		let mut options: Vec<(&str, String)> = Vec::new();

		if let Some(items) = self.custom {
			options.extend(items);
		};

		if let Some(items) = self.select {
			options.push(("$select", items.into_boxed_slice().join(",")));
		};

		if let Some(items) = self.expand {
			options.push(("$expand", items.into_boxed_slice().join(",")));
		};

		if let Some(items) = self.filter {
			options.push(("$filter", items.into_boxed_slice().join(" and ")));
		};

		if let Some(items) = self.order_by {
			options.push(("$orderBy", items.into_boxed_slice().join(",")));
		};

		if let Some(num) = self.top {
			options.push(("$top", num.to_string()));
		};

		if let Some(num) = self.skip {
			options.push(("$skip", num.to_string()));
		};

		// Convert OData options into URL query
		form_urlencoded::serialize(options)
	}
}

impl ToString for Parameters {
	fn to_string(&self) -> String {
		self.clone().into()
	}
}

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

	fn encode_pairs(v: Vec<(&str, &str)>) -> String {
		use url::form_urlencoded;
		form_urlencoded::serialize(v)
	}

	#[test]
	fn query_options_none() {
		let opts: String = Parameters::new()
			.into();
		assert_eq!(opts, "".to_string());
	}

	#[test]
	fn query_options_custom() {
		let opts: String = Parameters::new()
			.custom(vec![("a", "hello"), ("enable", "true")])
			.custom_add(("price", "20"))
			.into();
		assert_eq!(opts, encode_pairs(vec![("a", "hello"), ("enable", "true"), ("price", "20")]));
	}

	#[test]
	fn query_options_select() {
		let opts: String = Parameters::new()
			.select(vec!["Field1", "Field2", "3"])
			.into();
		assert_eq!(opts, encode_pairs(vec![("$select", "Field1,Field2,3")]));
	}

	#[test]
	fn query_options_select_add() {
		let opts: String = Parameters::new()
			.select_add("Field1")
			.select_add("Field2")
			.select_add("3")
			.into();
		assert_eq!(opts, encode_pairs(vec![("$select", "Field1,Field2,3")]));
	}

	#[test]
	fn query_options_expand() {
		let opts: String = Parameters::new()
			.expand(vec!["Children", "Siblings"])
			.into();
		assert_eq!(opts, encode_pairs(vec![("$expand", "Children,Siblings")]));
	}

	#[test]
	fn query_options_expand_add() {
		let opts: String = Parameters::new()
			.expand_add("Children")
			.expand_add("Siblings")
			.into();
		assert_eq!(opts, encode_pairs(vec![("$expand", "Children,Siblings")]));
	}

	#[test]
	fn query_options_filter() {
		let opts: String = Parameters::new()
			.filter(vec!["A eq B", "true"])
			.into();
		assert_eq!(opts, encode_pairs(vec![("$filter", "A eq B and true")]));
	}

	#[test]
	fn query_options_filter_add() {
		let opts: String = Parameters::new()
			.filter_add("A eq B")
			.filter_add("true")
			.into();
		assert_eq!(opts, encode_pairs(vec![("$filter", "A eq B and true")]));
	}

	#[test]
	fn query_options_order_by() {
		let opts: String = Parameters::new()
			.order_by(vec!["Date asc", "Time desc", "Id"])
			.into();
		assert_eq!(opts, encode_pairs(vec![("$orderBy", "Date asc,Time desc,Id")]));
	}

	#[test]
	fn query_options_order_by_add() {
		let opts: String = Parameters::new()
			.order_by_add("Date asc")
			.order_by_add("Time desc")
			.order_by_add("Id")
			.into();
		assert_eq!(opts, encode_pairs(vec![("$orderBy", "Date asc,Time desc,Id")]));
	}

	#[test]
	fn query_options_top() {
		let opts: String = Parameters::new()
			.top(10u32)
			.into();
		assert_eq!(opts, encode_pairs(vec![("$top", "10")]));
	}

	#[test]
	fn query_options_skip() {
		let opts: String = Parameters::new()
			.skip(9u32)
			.into();
		assert_eq!(opts, encode_pairs(vec![("$skip", "9")]));
	}

	#[test]
	fn query_options_all() {
		let opts: String = Parameters::new()
			.select(vec!["Field1", "Field2"])
			.select_add("3")
			.expand(vec!["Children"])
			.expand_add("Siblings")
			.filter(vec!["A eq B"])
			.filter_add("true")
			.order_by(vec!["Date asc", "Time desc"])
			.order_by_add("Id")
			.top(10u32)
			.skip(9u32)
			.into();

		let should_be = encode_pairs(vec![
				("$select", "Field1,Field2,3"),
				("$expand", "Children,Siblings"),
				("$filter", "A eq B and true"),
				("$orderBy", "Date asc,Time desc,Id"),
				("$top", "10"),
				("$skip", "9")
			]);

		assert_eq!(opts, should_be);
	}
}
<|endoftext|>


<commit_before>use arch::init;

pub type HandlerFunc = unsafe extern "C" fn();

#[derive(Debug, Clone)]
#[repr(C)]
struct ExceptionStackFrame {
    pub instruction_pointer: u64,
    pub code_segment: u64,
    pub cpu_flags: u64,
    pub stack_pointer: u64,
    pub stack_segment: u64,
}

#[derive(Debug, Clone)]
pub struct Exception {
    pub instruction_pointer: u64,
    pub code_segment: u64,
    pub cpu_flags: u64,
    pub stack_pointer: u64,
    pub stack_segment: u64,
    pub error_code: Option<u64>,
    pub exception_code: u64
}

macro_rules! save_registers {
    () => {
        asm!("push rax
              push rbx
              push rcx
              push rdx
              push rbp
              push rsi
              push rdi
              push r8
              push r9
              push r10
              push r11
              push r12
              push r13
              push r14
              push r15
              push rsp
        " :::: "intel", "volatile");
    }
}

macro_rules! restore_registers {
    () => {
        asm!("pop rsp
              pop r15
              pop r14
              pop r13
              pop r12
              pop r11
              pop r10
              pop r9
              pop r8
              pop rdi
              pop rsi
              pop rbp
              pop rdx
              pop rcx
              pop rbx
              pop rax
            " :::: "intel", "volatile");
    }
}

unsafe extern "C" fn set_kernel_stack(addr: u64) {
    init::set_kernel_stack(addr);
}

pub unsafe fn switch_to_raw(stack_vaddr: u64, code_start: u64, cpu_flags: u64) {
    let code_seg: u64 = 0x28 | 0x3;
    let data_seg: u64 = 0x30 | 0x3;

    asm!("call r15" :: "{rdi}"(stack_vaddr), "{rsi}"(code_start), "{rdx}"(cpu_flags), "{rcx}"(code_seg), "{r8}"(data_seg), "{r15}"(switch_to_raw_naked as unsafe extern "C" fn(u64, u64, u64, u64, u64)) :: "volatile", "intel");

    // WARNING: Everything below this before returning will not work.
}

#[no_mangle]
#[naked]
pub unsafe extern "C" fn switch_to_raw_naked(stack_vaddr: u64, code_start: u64, cpu_flags: u64, code_seg: u64, data_seg: u64) {
    save_registers!();

    asm!("mov rdi, rsp
          call $0" :: "i"(set_kernel_stack as unsafe extern "C" fn(u64)) : "rdi" : "volatile", "intel");

    asm!("push rax
          push rbx
          push r8
          push rcx
          push rdx
          iretq"
         :: "{rax}"(data_seg), "{rbx}"(stack_vaddr), "{rcx}"(code_seg), "{rdx}"(code_start), "{r8}"(cpu_flags)
         : "rax", "rbx", "rcx", "rdx",
           "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
         : "volatile", "intel");
}

static mut CUR_EXCEPTION_STACK_FRAME: Option<ExceptionStackFrame> = None;
static mut CUR_EXCEPTION_ERROR_CODE: Option<u64> = None;
static mut CUR_EXCEPTION_CODE: Option<u64> = None;

unsafe extern "C" fn store_exception_stack(exception_raw: *const ExceptionStackFrame, exception_code: u64) {
    let exception = unsafe {&*exception_raw};
    CUR_EXCEPTION_STACK_FRAME = Some(exception.clone());
    CUR_EXCEPTION_ERROR_CODE = None;
    CUR_EXCEPTION_CODE = Some(exception_code);
}

unsafe extern "C" fn store_error_exception_stack(exception_raw: *const ExceptionStackFrame, error_code: u64, exception_code: u64) {
    let exception = unsafe {&*exception_raw};
    CUR_EXCEPTION_STACK_FRAME = Some(exception.clone());
    CUR_EXCEPTION_ERROR_CODE = Some(error_code);
    CUR_EXCEPTION_CODE = Some(exception_code);
}

macro_rules! return_to_raw_fn {
    ($name: ident, $exception_code: expr) => (
        #[no_mangle]
        #[naked]
        pub unsafe extern "C" fn $name() {
            asm!("mov rdi, rsp
                  sub rsp, 8
                  call $0
                  add rsp, 48"
                 :: "i"(store_exception_stack as unsafe extern "C" fn(*const ExceptionStackFrame, u64)), "{rsi}"($exception_code)
                 :: "volatile", "intel");

            restore_registers!();
        }
    )
}

macro_rules! return_error_to_raw_fn {
    ($name: ident, $exception_code: expr) => (
        #[no_mangle]
        #[naked]
        pub unsafe extern "C" fn $name() {
            asm!("pop rsi
                  mov rdi, rsp
                  sub rsp, 8
                  call $0
                  add rsp, 48"
                 :: "i"(store_error_exception_stack as unsafe extern "C" fn(*const ExceptionStackFrame, u64)), "{rdx}"($exception_code)
                 :: "volatile", "intel");

            restore_registers!();
        }
    )
}

return_to_raw_fn!(keyboard_return_to_raw, 0x41);
return_to_raw_fn!(system_call_return_to_raw, 0x80);
return_to_raw_fn!(debug_call_return_to_raw, 0x81);

pub fn last_exception_return_value() -> Option<Exception> {
    unsafe {
        CUR_EXCEPTION_STACK_FRAME.clone().map(|exp| {
            Exception {
                instruction_pointer: exp.instruction_pointer,
                code_segment: exp.code_segment,
                cpu_flags: exp.cpu_flags,
                stack_pointer: exp.stack_pointer,
                stack_segment: exp.stack_segment,
                error_code: CUR_EXCEPTION_ERROR_CODE,
                exception_code: CUR_EXCEPTION_CODE.unwrap()
            }
        })
    }
}
<commit_msg>Explicitly enable interrupt in usermode<commit_after>use arch::init;

pub type HandlerFunc = unsafe extern "C" fn();

#[derive(Debug, Clone)]
#[repr(C)]
struct ExceptionStackFrame {
    pub instruction_pointer: u64,
    pub code_segment: u64,
    pub cpu_flags: u64,
    pub stack_pointer: u64,
    pub stack_segment: u64,
}

#[derive(Debug, Clone)]
pub struct Exception {
    pub instruction_pointer: u64,
    pub code_segment: u64,
    pub cpu_flags: u64,
    pub stack_pointer: u64,
    pub stack_segment: u64,
    pub error_code: Option<u64>,
    pub exception_code: u64
}

macro_rules! save_registers {
    () => {
        asm!("push rax
              push rbx
              push rcx
              push rdx
              push rbp
              push rsi
              push rdi
              push r8
              push r9
              push r10
              push r11
              push r12
              push r13
              push r14
              push r15
              push rsp
        " :::: "intel", "volatile");
    }
}

macro_rules! restore_registers {
    () => {
        asm!("pop rsp
              pop r15
              pop r14
              pop r13
              pop r12
              pop r11
              pop r10
              pop r9
              pop r8
              pop rdi
              pop rsi
              pop rbp
              pop rdx
              pop rcx
              pop rbx
              pop rax
            " :::: "intel", "volatile");
    }
}

unsafe extern "C" fn set_kernel_stack(addr: u64) {
    init::set_kernel_stack(addr);
}

pub unsafe fn switch_to_raw(stack_vaddr: u64, code_start: u64, cpu_flags: u64) {
    let code_seg: u64 = 0x28 | 0x3;
    let data_seg: u64 = 0x30 | 0x3;

    asm!("call r15" :: "{rdi}"(stack_vaddr), "{rsi}"(code_start), "{rdx}"(cpu_flags), "{rcx}"(code_seg), "{r8}"(data_seg), "{r15}"(switch_to_raw_naked as unsafe extern "C" fn(u64, u64, u64, u64, u64)) :: "volatile", "intel");

    // WARNING: Everything below this before returning will not work.
}

#[no_mangle]
#[naked]
pub unsafe extern "C" fn switch_to_raw_naked(stack_vaddr: u64, code_start: u64, cpu_flags: u64, code_seg: u64, data_seg: u64) {
    save_registers!();

    asm!("mov rdi, rsp
          call $0" :: "i"(set_kernel_stack as unsafe extern "C" fn(u64)) : "rdi" : "volatile", "intel");

    asm!("push rax
          push rbx
          push r8
          push rcx
          push rdx
          sti
          iretq"
         :: "{rax}"(data_seg), "{rbx}"(stack_vaddr), "{rcx}"(code_seg), "{rdx}"(code_start), "{r8}"(cpu_flags)
         : "rax", "rbx", "rcx", "rdx",
           "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
         : "volatile", "intel");
}

static mut CUR_EXCEPTION_STACK_FRAME: Option<ExceptionStackFrame> = None;
static mut CUR_EXCEPTION_ERROR_CODE: Option<u64> = None;
static mut CUR_EXCEPTION_CODE: Option<u64> = None;

unsafe extern "C" fn store_exception_stack(exception_raw: *const ExceptionStackFrame, exception_code: u64) {
    let exception = unsafe {&*exception_raw};
    CUR_EXCEPTION_STACK_FRAME = Some(exception.clone());
    CUR_EXCEPTION_ERROR_CODE = None;
    CUR_EXCEPTION_CODE = Some(exception_code);
}

unsafe extern "C" fn store_error_exception_stack(exception_raw: *const ExceptionStackFrame, error_code: u64, exception_code: u64) {
    let exception = unsafe {&*exception_raw};
    CUR_EXCEPTION_STACK_FRAME = Some(exception.clone());
    CUR_EXCEPTION_ERROR_CODE = Some(error_code);
    CUR_EXCEPTION_CODE = Some(exception_code);
}

macro_rules! return_to_raw_fn {
    ($name: ident, $exception_code: expr) => (
        #[no_mangle]
        #[naked]
        pub unsafe extern "C" fn $name() {
            asm!("mov rdi, rsp
                  sub rsp, 8
                  call $0
                  add rsp, 48"
                 :: "i"(store_exception_stack as unsafe extern "C" fn(*const ExceptionStackFrame, u64)), "{rsi}"($exception_code)
                 :: "volatile", "intel");

            restore_registers!();
        }
    )
}

macro_rules! return_error_to_raw_fn {
    ($name: ident, $exception_code: expr) => (
        #[no_mangle]
        #[naked]
        pub unsafe extern "C" fn $name() {
            asm!("pop rsi
                  mov rdi, rsp
                  sub rsp, 8
                  call $0
                  add rsp, 48"
                 :: "i"(store_error_exception_stack as unsafe extern "C" fn(*const ExceptionStackFrame, u64)), "{rdx}"($exception_code)
                 :: "volatile", "intel");

            restore_registers!();
        }
    )
}

return_to_raw_fn!(keyboard_return_to_raw, 0x41);
return_to_raw_fn!(system_call_return_to_raw, 0x80);
return_to_raw_fn!(debug_call_return_to_raw, 0x81);

pub fn last_exception_return_value() -> Option<Exception> {
    unsafe {
        CUR_EXCEPTION_STACK_FRAME.clone().map(|exp| {
            Exception {
                instruction_pointer: exp.instruction_pointer,
                code_segment: exp.code_segment,
                cpu_flags: exp.cpu_flags,
                stack_pointer: exp.stack_pointer,
                stack_segment: exp.stack_segment,
                error_code: CUR_EXCEPTION_ERROR_CODE,
                exception_code: CUR_EXCEPTION_CODE.unwrap()
            }
        })
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use antidote::RwLock;
use irc::client::data::User;
use irc::client::prelude::*;

use chrono::NaiveDateTime;
use humantime::format_duration;
use std::time::Duration;
use time;

use plugin::*;
use FrippyClient;

use self::error::*;
use error::ErrorKind as FrippyErrorKind;
use error::FrippyError;
use failure::Fail;
use failure::ResultExt;

pub mod database;
use self::database::Database;

#[derive(PluginName)]
pub struct Tell<T: Database, C> {
    tells: RwLock<T>,
    phantom: PhantomData<C>,
}

impl<T: Database, C: FrippyClient> Tell<T, C> {
    pub fn new(db: T) -> Self {
        Tell {
            tells: RwLock::new(db),
            phantom: PhantomData,
        }
    }

    fn tell_command(&self, client: &C, command: PluginCommand) -> Result<String, TellError> {
        if command.tokens.len() < 2 {
            return Ok(self.invalid_command().to_owned());
        }

        let mut online = Vec::new();

        let receivers = command.tokens[0].split(',').filter(|&s| !s.is_empty());
        let sender = command.source;

        let mut no_receiver = true;
        for receiver in receivers {
            if receiver.eq_ignore_ascii_case(client.current_nickname())
                || receiver.eq_ignore_ascii_case(&sender)
            {
                if !online.contains(&receiver) {
                    online.push(receiver);
                }
                continue;
            }

            let channels = client
                .list_channels()
                .expect("The irc crate should not be compiled with the \"nochanlists\" feature");

            let find_receiver = |option: Option<Vec<User>>| {
                option.and_then(|users| {
                    users
                        .into_iter()
                        .find(|user| user.get_nickname().eq_ignore_ascii_case(&receiver))
                })
            };

            if channels
                .iter()
                .map(|channel| client.list_users(&channel))
                .map(find_receiver)
                .any(|option| option.is_some())
            {
                if !online.contains(&receiver) {
                    online.push(receiver);
                }
                // TODO Change this when https://github.com/aatxe/irc/issues/136 gets resolved
                //continue;
            }

            let tm = time::now().to_timespec();
            let message = command.tokens[1..].join(" ");
            let tell = database::NewTellMessage {
                sender: &sender,
                receiver: &receiver.to_lowercase(),
                time: NaiveDateTime::from_timestamp(tm.sec, 0u32),
                message: &message,
            };

            debug!("Saving tell for {:?}", receiver);
            self.tells.write().insert_tell(&tell)?;
            no_receiver = false;
        }

        Ok(if no_receiver && online.is_empty() {
            String::from("Invalid receiver.")
        } else {
            match online.len() {
                0 => format!("Got it!"),
                1 => format!("{} is currently online.", online[0]),
                _ => format!("{} are currently online.", online.join(", ")),
            }
        })
    }

    fn on_namelist(&self, client: &C, channel: &str) -> Result<(), FrippyError> {
        let receivers = self.tells
            .read()
            .get_receivers()
            .context(FrippyErrorKind::Tell)?;

        if let Some(users) = client.list_users(channel) {
            debug!("Outstanding tells for {:?}", receivers);

            for receiver in users
                .iter()
                .map(|u| u.get_nickname())
                .filter(|u| receivers.iter().any(|r| r == &u.to_lowercase()))
            {
                self.send_tells(client, receiver)?;
            }

            Ok(())
        } else {
            Ok(())
        }
    }

    fn send_tells(&self, client: &C, receiver: &str) -> Result<(), FrippyError> {
        if client.current_nickname() == receiver {
            return Ok(());
        }

        let mut tells = self.tells.write();

        let tell_messages = match tells.get_tells(&receiver.to_lowercase()) {
            Ok(t) => t,
            Err(e) => {
                // This warning only occurs if frippy is built without a database
                #[allow(unreachable_patterns)]
                return match e.kind() {
                    ErrorKind::NotFound => Ok(()),
                    _ => Err(e.context(FrippyErrorKind::Tell))?,
                };
            }
        };

        for tell in tell_messages {
            let now = Duration::new(time::now().to_timespec().sec as u64, 0);
            let dur = now - Duration::new(tell.time.timestamp() as u64, 0);
            let human_dur = format_duration(dur);

            client
                .send_notice(
                    receiver,
                    &format!(
                        "Tell from {} {} ago: {}",
                        tell.sender, human_dur, tell.message
                    ),
                )
                .context(FrippyErrorKind::Connection)?;

            debug!(
                "Sent {:?} from {:?} to {:?}",
                tell.message, tell.sender, receiver
            );
        }

        tells
            .delete_tells(&receiver.to_lowercase())
            .context(FrippyErrorKind::Tell)?;

        Ok(())
    }

    fn invalid_command(&self) -> &str {
        "Incorrect Command. \
         Send \"tell help\" for help."
    }

    fn help(&self) -> &str {
        "Used to send messages to offline users which they will receive when they come online.\r\n
         usage: tell user message\r\n\
         example: tell Foobar Hello!"
    }
}

impl<T: Database, C: FrippyClient> Plugin for Tell<T, C> {
    type Client = C;
    fn execute(&self, client: &Self::Client, message: &Message) -> ExecutionStatus {
        let res = match message.command {
            Command::JOIN(_, _, _) => self.send_tells(client, message.source_nickname().unwrap()),
            Command::NICK(ref nick) => self.send_tells(client, nick),
            Command::PRIVMSG(ref nick, _) => self.send_tells(client, nick),
            Command::Response(resp, ref chan_info, _) => {
                if resp == Response::RPL_NAMREPLY {
                    debug!("NAMREPLY info: {:?}", chan_info);

                    self.on_namelist(client, &chan_info[chan_info.len() - 1])
                } else {
                    Ok(())
                }
            }
            _ => Ok(()),
        };

        match res {
            Ok(_) => ExecutionStatus::Done,
            Err(e) => ExecutionStatus::Err(e),
        }
    }

    fn execute_threaded(&self, _: &Self::Client, _: &Message) -> Result<(), FrippyError> {
        panic!("Tell should not use threading")
    }

    fn command(&self, client: &Self::Client, command: PluginCommand) -> Result<(), FrippyError> {
        if command.tokens.is_empty() {
            client
                .send_notice(&command.source, &self.invalid_command())
                .context(FrippyErrorKind::Connection)?;
            return Ok(());
        }

        let sender = command.source.to_owned();

        match command.tokens[0].as_ref() {
            "help" => client
                .send_notice(&command.source, &self.help())
                .context(FrippyErrorKind::Connection),
            _ => match self.tell_command(client, command) {
                Ok(msg) => client
                    .send_notice(&sender, &msg)
                    .context(FrippyErrorKind::Connection),
                Err(e) => client
                    .send_notice(&sender, &e.to_string())
                    .context(FrippyErrorKind::Connection),
            },
        }?;

        Ok(())
    }

    fn evaluate(&self, _: &Self::Client, _: PluginCommand) -> Result<String, String> {
        Err(String::from("This Plugin does not implement any commands."))
    }
}

use std::fmt;
impl<T: Database, C: FrippyClient> fmt::Debug for Tell<T, C> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Tell {{ ... }}")
    }
}

pub mod error {
    #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)]
    #[error = "TellError"]
    pub enum ErrorKind {
        /// Not found command error
        #[fail(display = "Tell was not found")]
        NotFound,

        /// MySQL error
        #[cfg(feature = "mysql")]
        #[fail(display = "Failed to execute MySQL Query")]
        MysqlError,

        /// No connection error
        #[cfg(feature = "mysql")]
        #[fail(display = "No connection to the database")]
        NoConnection,
    }
}
<commit_msg>Tell: Only show error if the message was not sent<commit_after>use std::marker::PhantomData;

use antidote::RwLock;
use irc::client::data::User;
use irc::client::prelude::*;

use chrono::NaiveDateTime;
use humantime::format_duration;
use std::time::Duration;
use time;

use plugin::*;
use FrippyClient;

use self::error::*;
use error::ErrorKind as FrippyErrorKind;
use error::FrippyError;
use failure::Fail;
use failure::ResultExt;

pub mod database;
use self::database::Database;

#[derive(PluginName)]
pub struct Tell<T: Database, C> {
    tells: RwLock<T>,
    phantom: PhantomData<C>,
}

impl<T: Database, C: FrippyClient> Tell<T, C> {
    pub fn new(db: T) -> Self {
        Tell {
            tells: RwLock::new(db),
            phantom: PhantomData,
        }
    }

    fn tell_command(&self, client: &C, command: PluginCommand) -> Result<String, TellError> {
        if command.tokens.len() < 2 {
            return Ok(self.invalid_command().to_owned());
        }

        let mut online = Vec::new();

        let receivers = command.tokens[0].split(',').filter(|&s| !s.is_empty());
        let sender = command.source;

        let mut no_receiver = true;
        for receiver in receivers {
            if receiver.eq_ignore_ascii_case(client.current_nickname())
                || receiver.eq_ignore_ascii_case(&sender)
            {
                if !online.contains(&receiver) {
                    online.push(receiver);
                }
                continue;
            }

            let channels = client
                .list_channels()
                .expect("The irc crate should not be compiled with the \"nochanlists\" feature");

            let find_receiver = |option: Option<Vec<User>>| {
                option.and_then(|users| {
                    users
                        .into_iter()
                        .find(|user| user.get_nickname().eq_ignore_ascii_case(&receiver))
                })
            };

            if channels
                .iter()
                .map(|channel| client.list_users(&channel))
                .map(find_receiver)
                .any(|option| option.is_some())
            {
                if !online.contains(&receiver) {
                    // online.push(receiver);
                }
                // TODO Change this when https://github.com/aatxe/irc/issues/136 gets resolved
                //continue;
            }

            let tm = time::now().to_timespec();
            let message = command.tokens[1..].join(" ");
            let tell = database::NewTellMessage {
                sender: &sender,
                receiver: &receiver.to_lowercase(),
                time: NaiveDateTime::from_timestamp(tm.sec, 0u32),
                message: &message,
            };

            debug!("Saving tell for {:?}", receiver);
            self.tells.write().insert_tell(&tell)?;
            no_receiver = false;
        }

        Ok(if no_receiver && online.is_empty() {
            String::from("Invalid receiver.")
        } else {
            match online.len() {
                0 => format!("Got it!"),
                1 => format!("{} is currently online.", online[0]),
                _ => format!("{} are currently online.", online.join(", ")),
            }
        })
    }

    fn on_namelist(&self, client: &C, channel: &str) -> Result<(), FrippyError> {
        let receivers = self.tells
            .read()
            .get_receivers()
            .context(FrippyErrorKind::Tell)?;

        if let Some(users) = client.list_users(channel) {
            debug!("Outstanding tells for {:?}", receivers);

            for receiver in users
                .iter()
                .map(|u| u.get_nickname())
                .filter(|u| receivers.iter().any(|r| r == &u.to_lowercase()))
            {
                self.send_tells(client, receiver)?;
            }

            Ok(())
        } else {
            Ok(())
        }
    }

    fn send_tells(&self, client: &C, receiver: &str) -> Result<(), FrippyError> {
        if client.current_nickname() == receiver {
            return Ok(());
        }

        let mut tells = self.tells.write();

        let tell_messages = match tells.get_tells(&receiver.to_lowercase()) {
            Ok(t) => t,
            Err(e) => {
                // This warning only occurs if frippy is built without a database
                #[allow(unreachable_patterns)]
                return match e.kind() {
                    ErrorKind::NotFound => Ok(()),
                    _ => Err(e.context(FrippyErrorKind::Tell))?,
                };
            }
        };

        for tell in tell_messages {
            let now = Duration::new(time::now().to_timespec().sec as u64, 0);
            let dur = now - Duration::new(tell.time.timestamp() as u64, 0);
            let human_dur = format_duration(dur);

            client
                .send_notice(
                    receiver,
                    &format!(
                        "Tell from {} {} ago: {}",
                        tell.sender, human_dur, tell.message
                    ),
                )
                .context(FrippyErrorKind::Connection)?;

            debug!(
                "Sent {:?} from {:?} to {:?}",
                tell.message, tell.sender, receiver
            );
        }

        tells
            .delete_tells(&receiver.to_lowercase())
            .context(FrippyErrorKind::Tell)?;

        Ok(())
    }

    fn invalid_command(&self) -> &str {
        "Incorrect Command. \
         Send \"tell help\" for help."
    }

    fn help(&self) -> &str {
        "Used to send messages to offline users which they will receive when they come online.\r\n
         usage: tell user message\r\n\
         example: tell Foobar Hello!"
    }
}

impl<T: Database, C: FrippyClient> Plugin for Tell<T, C> {
    type Client = C;
    fn execute(&self, client: &Self::Client, message: &Message) -> ExecutionStatus {
        let res = match message.command {
            Command::JOIN(_, _, _) => self.send_tells(client, message.source_nickname().unwrap()),
            Command::NICK(ref nick) => self.send_tells(client, nick),
            Command::PRIVMSG(ref nick, _) => self.send_tells(client, nick),
            Command::Response(resp, ref chan_info, _) => {
                if resp == Response::RPL_NAMREPLY {
                    debug!("NAMREPLY info: {:?}", chan_info);

                    self.on_namelist(client, &chan_info[chan_info.len() - 1])
                } else {
                    Ok(())
                }
            }
            _ => Ok(()),
        };

        match res {
            Ok(_) => ExecutionStatus::Done,
            Err(e) => ExecutionStatus::Err(e),
        }
    }

    fn execute_threaded(&self, _: &Self::Client, _: &Message) -> Result<(), FrippyError> {
        panic!("Tell should not use threading")
    }

    fn command(&self, client: &Self::Client, command: PluginCommand) -> Result<(), FrippyError> {
        if command.tokens.is_empty() {
            client
                .send_notice(&command.source, &self.invalid_command())
                .context(FrippyErrorKind::Connection)?;
            return Ok(());
        }

        let sender = command.source.to_owned();

        match command.tokens[0].as_ref() {
            "help" => client
                .send_notice(&command.source, &self.help())
                .context(FrippyErrorKind::Connection),
            _ => match self.tell_command(client, command) {
                Ok(msg) => client
                    .send_notice(&sender, &msg)
                    .context(FrippyErrorKind::Connection),
                Err(e) => client
                    .send_notice(&sender, &e.to_string())
                    .context(FrippyErrorKind::Connection),
            },
        }?;

        Ok(())
    }

    fn evaluate(&self, _: &Self::Client, _: PluginCommand) -> Result<String, String> {
        Err(String::from("This Plugin does not implement any commands."))
    }
}

use std::fmt;
impl<T: Database, C: FrippyClient> fmt::Debug for Tell<T, C> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Tell {{ ... }}")
    }
}

pub mod error {
    #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)]
    #[error = "TellError"]
    pub enum ErrorKind {
        /// Not found command error
        #[fail(display = "Tell was not found")]
        NotFound,

        /// MySQL error
        #[cfg(feature = "mysql")]
        #[fail(display = "Failed to execute MySQL Query")]
        MysqlError,

        /// No connection error
        #[cfg(feature = "mysql")]
        #[fail(display = "No connection to the database")]
        NoConnection,
    }
}
<|endoftext|>


<commit_before>use std::iter;
use std::fmt::{self, Debug};
use std::cmp::{Eq, PartialEq};
use std::ops::{Deref, DerefMut};
use rustwlc::{Geometry, Size, Point, WlcOutput};
use rustwlc::render::{write_pixels, wlc_pixel_format, BITS_PER_PIXEL};
use cairo::{self, Context, ImageSurface, Format, Operator, Status, SolidPattern};
use cairo::prelude::{SurfaceExt};

use super::draw::BaseDraw;

/// The borders of a container.
///
/// This type just deals with rendering,
#[derive(Clone)]
pub struct Borders {
    /// The surface that contains the bytes we give to wlc to draw.
    surface: ImageSurface,
    /// How thick the borders should be. This affects how big the geometry is.
    pub thickness: u32,
    /// The geometry where the buffer is written.
    ///
    /// Should correspond with the geometry of the container.
    pub geometry: Geometry
}

impl Borders {
    pub fn new(mut geometry: Geometry, thickness: u32) -> Self {
        // Add the thickness to the geometry.
        geometry.origin.x -= thickness as i32;
        geometry.origin.y -= thickness as i32;
        geometry.size.w += thickness;
        geometry.size.h += thickness;
        error!("Initial geometry: {:?}", geometry);
        let Size { w, h } = geometry.size;
        let stride = calculate_stride(w) as i32;
        // TODO Remove 100 so that we don't start with a gray ghost box
        let data: Vec<u8> = iter::repeat(0).take(h as usize * stride as usize).collect();
        let buffer = data.into_boxed_slice();
        let surface = ImageSurface::create_for_data(buffer,
                                                    drop_data,
                                                    Format::ARgb32,
                                                    w as i32,
                                                    h as i32,
                                                    stride);
        Borders {
            surface: surface,
            thickness: thickness,
            geometry: geometry
        }
    }

    pub fn render(&mut self) {
        warn!("Rendering {:#?}", self);
        let mut buffer = self.surface.get_data()
            .expect("Could not get border surface buffer");
        // TODO This doesn't seem right, wouldn't this break on multi-head output?
        let output_res = WlcOutput::focused().get_resolution()
            .expect("Could not get focused output's resolution");
        let mut geometry = self.geometry;

        // If the buffer would clip the side, keep it within the bounds
        // This is done because wlc wraps if it goes beyond, which we don't
        // want for the borders.
        if geometry.origin.x < 0 {
            geometry.origin.x = 0;
        }
        if geometry.origin.x + geometry.size.w as i32 > output_res.w as i32 {
            let offset = (geometry.origin.x + geometry.size.w as i32) - output_res.w as i32;
            geometry.origin.x -= offset as i32;
        }
        if geometry.origin.y + geometry.size.h as i32 > output_res.h as i32 {
            let offset = (geometry.origin.y + geometry.size.h as i32) - output_res.h as i32;
            geometry.origin.y -= offset as i32;
        }
        if geometry.origin.y < 0 {
            geometry.origin.y = 0;
        }
        //error!("Rendering (abs) @ {:#?}", geometry);
        write_pixels(wlc_pixel_format::WLC_RGBA8888, geometry, &mut buffer);
    }

    /// Updates the position at which we render the buffer.
    ///
    /// Since this is a common operation, and does not resize the buffer,
    /// this is a method is here instead of in a draw struct
    /// for ergonomic and performance reasons.
    pub fn update_pos(&mut self, origin: Point) {
        self.geometry.origin = origin;
    }

    /// Updates/Creates the underlying geometry for the surface/buffer.
    ///
    /// This causes a reallocation of the buffer, do not call this
    /// in a tight loop unless you want memory fragmentation and
    /// bad performance.
    pub fn reallocate_buffer(&mut self, mut geometry: Geometry) {
        // Add the thickness to the geometry.
        error!("Reallocating buffer!");
        geometry.origin.x -= self.thickness as i32;
        geometry.origin.y -= self.thickness as i32;
        geometry.size.w += self.thickness;
        geometry.size.h += self.thickness;
        let Size { w, h } = geometry.size;
        if w == self.geometry.size.w && h == self.geometry.size.h {
            warn!("Geometry is same size, not reallocating");
            return;
        }
        let stride = calculate_stride(w) as i32;
        // TODO Remove 100 so that we don't start with a gray ghost box
        //let data = Vec::with_capacity(h as usize * stride as usize);
        let data: Vec<u8> = iter::repeat(0).take(h as usize * stride as usize).collect();
        let buffer = data.into_boxed_slice();
        let surface = ImageSurface::create_for_data(buffer,
                                                    drop_data,
                                                    Format::ARgb32,
                                                    w as i32,
                                                    h as i32,
                                                    stride);
        self.geometry = geometry;
        self.surface = surface;
    }

    /// Enables Cairo drawing capabilities on the borders.
    ///
    /// While drawing with Cairo, the underlying surface cannot be read.
    /// Borders is consumed in order for this to be checked at compile time.
    pub fn enable_cairo(self) -> Result<BaseDraw, cairo::Status> {
        let cairo = Context::new(&self.surface);
        match cairo.status() {
            cairo::Status::Success => {},
            err => return Err(err)
        }
        cairo.set_operator(Operator::Source);
        match cairo.status() {
            cairo::Status::Success => {},
            err => return Err(err)
        }
        Ok(BaseDraw::new(self, cairo))
    }
}

impl Debug for Borders {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Borders")
            .field("geometry", &self.geometry as &Debug)
            .field("thickness", &self.thickness as &Debug)
            .finish()
    }
}

impl PartialEq for Borders {
    fn eq(&self, other: &Borders) -> bool {
        self.geometry == other.geometry
    }
}

impl Eq for Borders {}

unsafe impl Send for Borders {}
unsafe impl Sync for Borders {}

/// Calculates the stride for ARgb32 encoded buffers
fn calculate_stride(width: u32) -> u32 {
    // function stolen from CAIRO_STRIDE_FOR_WIDTH macro in cairoint.h
    // Can be found in the most recent version of the cairo source
    let stride_alignment = ::std::mem::size_of::<u32>() as u32;
    ((BITS_PER_PIXEL * width + 7 ) / 8 + (stride_alignment - 1))  & (stride_alignment.overflowing_neg().0)
}

#[allow(dead_code)]
fn drop_data(_: Box<[u8]>) { error!("Freeing data") }
<commit_msg>Removed unhelpful debugging statements for cur prb<commit_after>use std::iter;
use std::fmt::{self, Debug};
use std::cmp::{Eq, PartialEq};
use std::ops::{Deref, DerefMut};
use rustwlc::{Geometry, Size, Point, WlcOutput};
use rustwlc::render::{write_pixels, wlc_pixel_format, BITS_PER_PIXEL};
use cairo::{self, Context, ImageSurface, Format, Operator, Status, SolidPattern};
use cairo::prelude::{SurfaceExt};

use super::draw::BaseDraw;

/// The borders of a container.
///
/// This type just deals with rendering,
#[derive(Clone)]
pub struct Borders {
    /// The surface that contains the bytes we give to wlc to draw.
    surface: ImageSurface,
    /// How thick the borders should be. This affects how big the geometry is.
    pub thickness: u32,
    /// The geometry where the buffer is written.
    ///
    /// Should correspond with the geometry of the container.
    pub geometry: Geometry
}

impl Borders {
    pub fn new(mut geometry: Geometry, thickness: u32) -> Self {
        // Add the thickness to the geometry.
        geometry.origin.x -= thickness as i32;
        geometry.origin.y -= thickness as i32;
        geometry.size.w += thickness;
        geometry.size.h += thickness;
        error!("Initial geometry: {:?}", geometry);
        let Size { w, h } = geometry.size;
        let stride = calculate_stride(w) as i32;
        // TODO Remove 100 so that we don't start with a gray ghost box
        let data: Vec<u8> = iter::repeat(0).take(h as usize * stride as usize).collect();
        let buffer = data.into_boxed_slice();
        let surface = ImageSurface::create_for_data(buffer,
                                                    drop_data,
                                                    Format::ARgb32,
                                                    w as i32,
                                                    h as i32,
                                                    stride);
        Borders {
            surface: surface,
            thickness: thickness,
            geometry: geometry
        }
    }

    pub fn render(&mut self) {
        warn!("Rendering {:#?}", self);
        let mut buffer = self.surface.get_data()
            .expect("Could not get border surface buffer");
        // TODO This doesn't seem right, wouldn't this break on multi-head output?
        let output_res = WlcOutput::focused().get_resolution()
            .expect("Could not get focused output's resolution");
        let mut geometry = self.geometry;

        // If the buffer would clip the side, keep it within the bounds
        // This is done because wlc wraps if it goes beyond, which we don't
        // want for the borders.
        if geometry.origin.x < 0 {
            geometry.origin.x = 0;
        }
        if geometry.origin.x + geometry.size.w as i32 > output_res.w as i32 {
            let offset = (geometry.origin.x + geometry.size.w as i32) - output_res.w as i32;
            geometry.origin.x -= offset as i32;
        }
        if geometry.origin.y + geometry.size.h as i32 > output_res.h as i32 {
            let offset = (geometry.origin.y + geometry.size.h as i32) - output_res.h as i32;
            geometry.origin.y -= offset as i32;
        }
        if geometry.origin.y < 0 {
            geometry.origin.y = 0;
        }
        error!("Rendering (abs) @ {:#?}", geometry);
        write_pixels(wlc_pixel_format::WLC_RGBA8888, geometry, &mut buffer);
    }

    /// Updates the position at which we render the buffer.
    ///
    /// Since this is a common operation, and does not resize the buffer,
    /// this is a method is here instead of in a draw struct
    /// for ergonomic and performance reasons.
    pub fn update_pos(&mut self, origin: Point) {
        self.geometry.origin = origin;
    }

    /// Updates/Creates the underlying geometry for the surface/buffer.
    ///
    /// This causes a reallocation of the buffer, do not call this
    /// in a tight loop unless you want memory fragmentation and
    /// bad performance.
    pub fn reallocate_buffer(&mut self, mut geometry: Geometry) {
        // Add the thickness to the geometry.
        error!("setting underlying border geometry to {:#?}", geometry);
        //error!("Reallocating buffer!");
        geometry.origin.x -= self.thickness as i32;
        geometry.origin.y -= self.thickness as i32;
        geometry.size.w += self.thickness;
        geometry.size.h += self.thickness;
        let Size { w, h } = geometry.size;
        if w == self.geometry.size.w && h == self.geometry.size.h {
            //warn!("Geometry is same size, not reallocating");
            return;
        }
        let stride = calculate_stride(w) as i32;
        // TODO Remove 100 so that we don't start with a gray ghost box
        //let data = Vec::with_capacity(h as usize * stride as usize);
        let data: Vec<u8> = iter::repeat(0).take(h as usize * stride as usize).collect();
        let buffer = data.into_boxed_slice();
        let surface = ImageSurface::create_for_data(buffer,
                                                    drop_data,
                                                    Format::ARgb32,
                                                    w as i32,
                                                    h as i32,
                                                    stride);
        self.geometry = geometry;
        self.surface = surface;
    }

    /// Enables Cairo drawing capabilities on the borders.
    ///
    /// While drawing with Cairo, the underlying surface cannot be read.
    /// Borders is consumed in order for this to be checked at compile time.
    pub fn enable_cairo(self) -> Result<BaseDraw, cairo::Status> {
        let cairo = Context::new(&self.surface);
        match cairo.status() {
            cairo::Status::Success => {},
            err => return Err(err)
        }
        cairo.set_operator(Operator::Source);
        match cairo.status() {
            cairo::Status::Success => {},
            err => return Err(err)
        }
        Ok(BaseDraw::new(self, cairo))
    }
}

impl Debug for Borders {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Borders")
            .field("geometry", &self.geometry as &Debug)
            .field("thickness", &self.thickness as &Debug)
            .finish()
    }
}

impl PartialEq for Borders {
    fn eq(&self, other: &Borders) -> bool {
        self.geometry == other.geometry
    }
}

impl Eq for Borders {}

unsafe impl Send for Borders {}
unsafe impl Sync for Borders {}

/// Calculates the stride for ARgb32 encoded buffers
fn calculate_stride(width: u32) -> u32 {
    // function stolen from CAIRO_STRIDE_FOR_WIDTH macro in cairoint.h
    // Can be found in the most recent version of the cairo source
    let stride_alignment = ::std::mem::size_of::<u32>() as u32;
    ((BITS_PER_PIXEL * width + 7 ) / 8 + (stride_alignment - 1))  & (stride_alignment.overflowing_neg().0)
}

#[allow(dead_code)]
fn drop_data(_: Box<[u8]>) { /*error!("Freeing data")*/ }
<|endoftext|>


<commit_before>#[feature(macro_rules)];
use std::{cast};

// emulating C++ classes using Traits as vtables, could the safety be improved?

pub trait Foo {
	fn foo(&self,i:int);
}

pub struct CppClass<RawDataStruct,TraitInterface> {
	priv vtable_ptr: *(),	// you must not change this :(
							// it is a ptr to the vtable
	dat:RawDataStruct
}

impl<Struct,Trait> Deref<Struct> for  CppClass<Struct,Trait> {
	fn deref<'a> (&'a self)->&'a Struct { &self.dat }
}
impl<Struct,Trait> DerefMut<Struct> for  CppClass<Struct,Trait> {
	fn deref_mut<'a> (&'a mut self)->&'a mut Struct { &mut self.dat }
}
/*
// TODO - we can't get this to work.
impl<Struct,T> Deref<T> for  CppClass<Struct,&'static T> {
	fn deref<'a> (&'a self)->&'a T { //&'a self.as_trait()
		unsafe {cast::transmute::<_,&'a T>( (self.vtable_ptr, &self.dat) )}
	}
}
impl<Struct,T> DerefMut<T> for  CppClass<Struct,&'static T> {
	fn deref_mut<'a> (&'a mut self)->&'a mut T { //&'a self.as_trait()
		unsafe {cast::transmute::<_,&'a mut T>( (self.vtable_ptr, &mut self.dat) )}
	}
}
*/

impl<Struct,Trait>  CppClass<Struct,Trait> {
	pub fn as_trait<'a>(&'a self)->Trait  {
	    unsafe {
			cast::transmute::<_,Trait>( (self.vtable_ptr, &self.dat) )
		}
	}
	pub fn data<'a>(&'a self)->&'a Struct { &'a self.dat }
	pub fn data_mut<'a>(&'a mut self)->&'a mut Struct { &'a mut self.dat }
}

macro_rules! new_class {

	($tname:ty for $sname:ident { $($field:ident : $val:expr),* })=>{
		// todo: we can't make initializer list work for arbitrary type,
		// so add another rule to accept a constructor function for non ident type.
		CppClass::<$sname,& $tname> {
			vtable_ptr:unsafe {
				let null_obj=cast::transmute::<_,&'static $sname>(0);
				let (vt,_):(*u8,*u8)=
					cast::transmute(null_obj as &'static $tname);
				cast::transmute(vt)
			},

			dat: $sname { $($field: $val),* }
		}
	}
}

struct Banana { x:int }
impl Foo for Banana {
	fn foo(&self,i:int) {
		println!("hello from banana.foo {:?} {:?} {:?}",i, self.x, i+self.x);
	}
}

macro_rules! repeat {
	(($it:ident=$it_init:expr ; $condition:expr ; $inc:expr)  $($e:expr);*)=>
	{
		{
			let mut $it=$it_init;
			while $condition {
				let ret={$($e);*};
				$inc;
				ret
			}
		}

	}
}

fn main() {
	let mut b :CppClass<Banana,&Foo> = new_class!( Foo for Banana  {x:10} );
	b.dat.x=10;
	// can you write to 'vtable_ptr' unsafely?

	b.as_trait().foo(3);

	repeat!{(i=0; i<10; i+=1)
		println!("{}",i)
	}

}
<commit_msg>added data accessors, but couldn't get deref to return trait automatically<commit_after>#[feature(macro_rules)];
use std::{cast};

// emulating C++ classes using Traits as vtables, could the safety be improved?

pub trait Foo {
	fn foo(&self,i:int);
}

pub struct CppClass<RawDataStruct,TraitInterface> {
	priv vtable_ptr: *(),	// you must not change this :(
							// it is a ptr to the vtable
	dat:RawDataStruct
}

impl<Struct,Trait> Deref<Struct> for  CppClass<Struct,Trait> {
	fn deref<'a> (&'a self)->&'a Struct { &self.dat }
}
impl<Struct,Trait> DerefMut<Struct> for  CppClass<Struct,Trait> {
	fn deref_mut<'a> (&'a mut self)->&'a mut Struct { &mut self.dat }
}
/*
// TODO - we can't get this to work.
impl<Struct,T> Deref<T> for  CppClass<Struct,&'static T> {
	fn deref<'a> (&'a self)->&'a T { //&'a self.as_trait()
		unsafe {cast::transmute::<_,&'a T>( (self.vtable_ptr, &self.dat) )}
	}
}
impl<Struct,T> DerefMut<T> for  CppClass<Struct,&'static T> {
	fn deref_mut<'a> (&'a mut self)->&'a mut T { //&'a self.as_trait()
		unsafe {cast::transmute::<_,&'a mut T>( (self.vtable_ptr, &mut self.dat) )}
	}
}
*/

impl<Struct,Trait>  CppClass<Struct,Trait> {
	pub fn as_trait<'a>(&'a self)->Trait  {
	    unsafe {
			cast::transmute::<_,Trait>( (self.vtable_ptr, &self.dat) )
		}
	}
	pub fn data<'a>(&'a self)->&'a Struct { &'a self.dat }
	pub fn data_mut<'a>(&'a mut self)->&'a mut Struct { &'a mut self.dat }
}

macro_rules! new_class {

	($tname:ty for $sname:ident { $($field:ident : $val:expr),* })=>{
		// todo: we can't make initializer list work for arbitrary type,
		// so add another rule to accept a constructor function for non ident type.
		CppClass::<$sname,& $tname> {
			vtable_ptr:unsafe {
				let null_obj=cast::transmute::<_,&'static $sname>(0);
				let (vt,_):(*u8,*u8)=
					cast::transmute(null_obj as &'static $tname);
				cast::transmute(vt)
			},

			dat: $sname { $($field: $val),* }
		}
	}
}

struct Banana { x:int }
impl Foo for Banana {
	fn foo(&self,i:int) {
		println!("hello from banana.foo {:?} {:?} {:?}",i, self.x, i+self.x);
	}
}

macro_rules! forr {
	( ($($it:ident=$it_init:expr),* ; $condition:expr ; $($inc:expr),*)  $($e:expr);*)=>
	{
		{
			$(let mut $it=$it_init);*;
			while $condition {
				let ret={$($e);*};
				$($inc);*;
				ret
			}
		}

	}
}

fn main() {
	let mut b :CppClass<Banana,&Foo> = new_class!( Foo for Banana  {x:10} );
	b.dat.x=10;
	// can you write to 'vtable_ptr' unsafely?

	b.as_trait().foo(3);

	forr!{(i=0,j=0; i<10; i+=1,j+=2)
		println!("{} {}",i,j)
	}

	let x=
	forr!{(i=0,acc=0; i<10; i+=1)
		println!("{} {}",i,j); acc+=i; acc
	}

}
<|endoftext|>


<commit_before>//These benchmarks should currently not be considered complete, extensive or significant.
//Also indexing is currently too slow. So using them is not really fun.
#![feature(test)]
extern crate rand;
extern crate test;
extern crate perlin;
#[macro_use]
extern crate lazy_static;

mod utils;

use utils::*;

use perlin::index::boolean_index::BooleanIndex;

lazy_static!{
    pub static ref INDICES: [BooleanIndex<usize>; 3] = [
        prepare_index(1_000, 500), //1.000 documents with 500 terms a 8bytes = 4MB
        prepare_index(10_000, 500), //10.000 documents with 500 terms a 8bytes = 40MB
        prepare_index(1_000, 500), //100.000 documents with 5000 terms a 8bytes = 400MB
    ];
}

macro_rules! bench {
    ($query:expr) =>
    {

        #[bench]
        fn typical_first_ten(b: &mut Bencher) {
            b.iter(||
                black_box(INDICES[0].execute_query($query).take(10).count())
            );
        }

        #[bench]
        fn large_collection_first_ten(b: &mut Bencher) {
            b.iter(||
                black_box(INDICES[1].execute_query($query).take(10).count())
            );
        }

        #[bench]
        fn huge_collection_first_ten(b: &mut Bencher) {
            b.iter(||
                black_box(INDICES[2].execute_query($query).take(10).count())
            );
        }

        #[bench]
        fn typical(b: &mut Bencher) {
            b.iter(||
                black_box(INDICES[0].execute_query($query).count())
            );
        }

        #[bench]
        fn large_collection(b: &mut Bencher) {
            b.iter(||
                black_box(INDICES[1].execute_query($query).count())
            );
        }

        #[bench]
        fn huge_collection(b: &mut Bencher) {
            b.iter(||
                black_box(INDICES[2].execute_query($query).count())
            );
        }
    }
}

macro_rules! build_bench {
    ($name:ident, $query:expr) => (
        mod $name {
            use super::*;
            use test::Bencher;
            use perlin::index::boolean_index::*;
            use perlin::index::Index;
            use test::black_box;
            bench!{$query}
        }

    )

}

build_bench!(atom_frequent, &QueryBuilder::atom(4).build());
build_bench!(atom_seldom, &QueryBuilder::atom(4000).build());
<commit_msg>expand benches for querying<commit_after>//These benchmarks should currently not be considered complete, extensive or significant.
//Also indexing is currently too slow. So using them is not really fun.
#![feature(test)]
extern crate rand;
extern crate test;
extern crate perlin;
#[macro_use]
extern crate lazy_static;

mod utils;

use utils::*;

use perlin::index::boolean_index::BooleanIndex;

lazy_static!{
    pub static ref INDICES: [BooleanIndex<usize>; 3] = [
        prepare_index(1_000, 500), //1.000 documents with 500 terms a 8bytes = 4MB
        prepare_index(10_000, 500), //10.000 documents with 500 terms a 8bytes = 40MB
        prepare_index(1_000, 5000), //100.000 documents with 1000 terms a 8bytes = 800MB
    ];
}

macro_rules! bench {
    ($query:expr) =>
    {

        #[bench]
        fn typical_first_ten(b: &mut Bencher) {
            b.iter(||
                black_box(INDICES[0].execute_query($query).take(10).count())
            );
        }

        #[bench]
        fn large_collection_first_ten(b: &mut Bencher) {
            b.iter(||
                black_box(INDICES[1].execute_query($query).take(10).count())
            );
        }

        #[bench]
        fn large_documents_first_ten(b: &mut Bencher) {
            b.iter(||
                black_box(INDICES[2].execute_query($query).take(10).count())
            );
        }

        #[bench]
        fn typical(b: &mut Bencher) {
            b.iter(||
                black_box(INDICES[0].execute_query($query).count())
            );
        }

        #[bench]
        fn large_collection(b: &mut Bencher) {
            b.iter(||
                black_box(INDICES[1].execute_query($query).count())
            );
        }

        #[bench]
        fn large_documents_collection(b: &mut Bencher) {
            b.iter(||
                black_box(INDICES[2].execute_query($query).count())
            );
        }
    }
}

macro_rules! build_bench {
    ($name:ident, $query:expr) => (
        mod $name {
            use super::*;
            use test::Bencher;
            use perlin::index::boolean_index::*;
            use perlin::index::Index;
            use test::black_box;
            bench!{$query}
        }

    )

}

build_bench!(and_seldom_seldom, &QueryBuilder::and(QueryBuilder::atoms(vec![4000, 4002])).build());
build_bench!(and_frequent_seldom, &QueryBuilder::and(QueryBuilder::atoms(vec![4, 4002])).build());
build_bench!(and_frequent_frequent, &QueryBuilder::and(QueryBuilder::atoms(vec![4, 5])).build());
build_bench!(atom_frequent, &QueryBuilder::atom(4).build());
build_bench!(atom_seldom, &QueryBuilder::atom(4000).build());
<|endoftext|>