<commit_before>// Copyright (c) 2017-2020, 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 1\n").unwrap();
  if env::var("CARGO_CFG_TARGET_OS").unwrap() == "macos" {
    config_file.write(b" %define PREFIX 1\n").unwrap();
  }

  let asm_files = &[
    "src/x86/ipred_avx2.asm",
    "src/x86/ipred_sse.asm",
    "src/x86/ipred16_avx2.asm",
    "src/x86/itx_avx2.asm",
    "src/x86/itx_sse.asm",
    "src/x86/itx16_avx2.asm",
    "src/x86/looprestoration_avx2.asm",
    "src/x86/looprestoration16_avx2.asm",
    "src/x86/mc_avx2.asm",
    "src/x86/mc16_avx2.asm",
    "src/x86/mc_avx512.asm",
    "src/x86/mc_sse.asm",
    "src/x86/me.asm",
    "src/x86/sad_sse2.asm",
    "src/x86/sad_avx.asm",
    "src/x86/satd.asm",
    "src/x86/sse.asm",
    "src/x86/cdef_rav1e.asm",
    "src/x86/cdef_sse.asm",
    "src/x86/cdef16_avx2.asm",
    "src/x86/cdef16_sse.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('/');
    let mut nasm = nasm_rs::Build::new();
    for file in asm_files {
      nasm.file(file);
    }
    nasm.flag(&config_include_arg);
    nasm.flag("-Isrc/");
    let obj = nasm.compile_objects().expect(
      "NASM build failed. Make sure you have nasm installed. https://nasm.us",
    );
    // cc is better at finding the correct archiver
    let mut cc = cc::Build::new();
    for o in obj {
      cc.object(o);
    }
    cc.compile("rav1easm");

    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();
  if env::var("CARGO_CFG_TARGET_OS").unwrap() == "macos" {
    config_file.write(b" #define PREFIX 1\n").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/cdef.S",
    "src/arm/64/cdef16.S",
    "src/arm/64/mc.S",
    "src/arm/64/mc16.S",
    "src/arm/64/itx.S",
    "src/arm/64/itx16.S",
    "src/arm/64/ipred.S",
    "src/arm/64/ipred16.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 the CI
  // Make sure to updated README.md when this changes.
  const REQUIRED_VERSION: &str = "1.51.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>Support more Apple aarch64 systems<commit_after>// Copyright (c) 2017-2020, 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 1\n").unwrap();
  if env::var("CARGO_CFG_TARGET_VENDOR").unwrap() == "apple" {
    config_file.write(b" %define PREFIX 1\n").unwrap();
  }

  let asm_files = &[
    "src/x86/ipred_avx2.asm",
    "src/x86/ipred_sse.asm",
    "src/x86/ipred16_avx2.asm",
    "src/x86/itx_avx2.asm",
    "src/x86/itx_sse.asm",
    "src/x86/itx16_avx2.asm",
    "src/x86/looprestoration_avx2.asm",
    "src/x86/looprestoration16_avx2.asm",
    "src/x86/mc_avx2.asm",
    "src/x86/mc16_avx2.asm",
    "src/x86/mc_avx512.asm",
    "src/x86/mc_sse.asm",
    "src/x86/me.asm",
    "src/x86/sad_sse2.asm",
    "src/x86/sad_avx.asm",
    "src/x86/satd.asm",
    "src/x86/sse.asm",
    "src/x86/cdef_rav1e.asm",
    "src/x86/cdef_sse.asm",
    "src/x86/cdef16_avx2.asm",
    "src/x86/cdef16_sse.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('/');
    let mut nasm = nasm_rs::Build::new();
    for file in asm_files {
      nasm.file(file);
    }
    nasm.flag(&config_include_arg);
    nasm.flag("-Isrc/");
    let obj = nasm.compile_objects().expect(
      "NASM build failed. Make sure you have nasm installed. https://nasm.us",
    );
    // cc is better at finding the correct archiver
    let mut cc = cc::Build::new();
    for o in obj {
      cc.object(o);
    }
    cc.compile("rav1easm");

    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();
  if env::var("CARGO_CFG_TARGET_VENDOR").unwrap() == "apple" {
    config_file.write(b" #define PREFIX 1\n").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/cdef.S",
    "src/arm/64/cdef16.S",
    "src/arm/64/mc.S",
    "src/arm/64/mc16.S",
    "src/arm/64/itx.S",
    "src/arm/64/itx16.S",
    "src/arm/64/ipred.S",
    "src/arm/64/ipred16.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 the CI
  // Make sure to updated README.md when this changes.
  const REQUIRED_VERSION: &str = "1.51.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>// Implements http://rosettacode.org/wiki/N-queens_problem

extern crate test;

use std::vec::Vec;
use std::iter::AdditiveIterator;

#[cfg(test)]
use test::Bencher;

#[cfg(not(test))]
fn main() {
    for num in range(0i32, 16) {
        println!("Sequential: {}: {}", num, n_queens(num));
    }
    for num in range(0i32, 16) {
        println!("Parallel: {}: {}", num, semi_parallel_n_queens(num));
    }
}

/*           _
   ___  ___ | |_   _____ _ __
  / __|/ _ \| \ \ / / _ \ '__/
  \__ \ (_) | |\ V /  __/ |
  |___/\___/|_| \_/ \___|_|

*/

// Solves n-queens using a depth-first, backtracking solution.
// Returns the number of solutions for a given n.
fn n_queens(n: i32) -> uint {
    // Pass off to our helper function.
    return n_queens_helper((1 << n as uint) -1, 0, 0, 0);
}

// The meat of the algorithm is in here, a recursive helper function
// that actually computes the answer using a depth-first, backtracking
// algorithm.
//
// The 30,000 foot overview is as follows:
//
// This function takes only 3 important parameters: three integers
// which represent the spots on the current row that are blocked
// by previous queens.
//
// The "secret sauce" here is that we can avoid passing around the board
// or even the locations of the previous queens and instead we use this
// information to infer the conflicts for the next row.
//
// Once we know the conflicts in our current row we can simply recurse
// over all of the open spots and profit.
//
// This implementation is optimized for speed and memory by using
// integers and bit shifting instead of arrays for storing the conflicts.
fn n_queens_helper(all_ones: i32, left_diags: i32, columns: i32, right_diags: i32) -> uint {
    // all_ones is a special value that simply has all 1s in the first n positions
    // and 0s elsewhere. We can use it to clear out areas that we don't care about.

    // Our solution count.
    // This will be updated by the recursive calls to our helper.
    let mut solutions = 0;

    // We get validSpots with some bit trickery. Effectively, each of the parameters
    // can be ORed together to create an integer with all the conflicts together,
    // which we then invert and limit by ANDing with all_ones, our special value
    //from earlier.
    let mut valid_spots = !(left_diags | columns | right_diags) & all_ones;

    // Since valid_spots contains 1s in all of the locations that
    // are conflict-free, we know we have gone through all of
    // those locations when valid_spots is all 0s, i.e. when it is 0.
    while valid_spots != 0 {
        // This is just bit trickery. For reasons involving the weird
        // behavior of two's complement integers, this creates an integer
        // which is all 0s except for a single 1 in the position of the
        // LSB of valid_spots.
        let spot = -valid_spots & valid_spots;

        // We then XOR that integer with the validSpots to flip it to 0
        // in valid_spots.
        valid_spots = valid_spots ^ spot;

        // Make a recursive call. This is where we infer the conflicts
        // for the next row.
        solutions += n_queens_helper(
            all_ones,
            // We add a conflict in the current spot and then shift left,
            // which has the desired effect of moving all of the conflicts
            // that are created by left diagonals to the left one square.
            (left_diags | spot) << 1,

            // For columns we simply mark this column as filled by ORing
            // in the currentSpot.
            (columns | spot),

            // This is the same as the left_diag shift, except we shift
            // right because these conflicts are caused by right diagonals.
            (right_diags | spot) >> 1);
    }

    // If columns is all blocked (i.e. if it is all ones) then we
    // have arrived at a solution because we have placed n queens.
    solutions + ((columns == all_ones) as uint)
}

// This is the same as the regular nQueens except it creates
// n threads in which to to do the work.
//
// This is much slower for smaller numbers (under 16~17) but outperforms
// the sequential algorithm after that.
fn semi_parallel_n_queens(n: i32) -> uint {
    let all_ones = (1 << n as uint) - 1;
    let (columns, left_diags, right_diags) = (0, 0, 0);

    let mut receivers = Vec::new();
    let mut valid_spots = !(left_diags | columns | right_diags) & all_ones;
    while valid_spots != 0 {
        let (tx, rx) = channel();
        let spot = -valid_spots & valid_spots;
        valid_spots = valid_spots ^ spot;
        receivers.push(rx);

        spawn(proc() {
            tx.send(n_queens_helper(all_ones,
                                    (left_diags | spot) << 1,
                                    (columns | spot),
                                    (right_diags | spot) >> 1));
        });
    }

    receivers.iter().map(|r| r.recv()).sum() + ((columns == all_ones) as uint)
}

// Tests

#[test]
fn test_n_queens() {
    let real = vec!(1, 1, 0, 0, 2, 10, 4, 40, 92u);
    for num in range(0, 9i32) {
        assert_eq!(n_queens(num), *real.get(num as uint));
    }
}

#[test]
fn test_parallel_n_queens() {
    let real = vec!(1, 1, 0, 0, 2, 10, 4, 40, 92u);
    for num in range(0, 9i32) {
        assert_eq!(semi_parallel_n_queens(num), *real.get(num as uint));
    }
}

#[bench]
fn bench_n_queens(b: &mut Bencher) {
    b.iter(|| { test::black_box(n_queens(16)); });
}

#[bench]
fn bench_semi_parallel_n_queens(b: &mut Bencher) {
    b.iter(|| { test::black_box(semi_parallel_n_queens(16)); });
}
<commit_msg>n_queens .get to index<commit_after>// Implements http://rosettacode.org/wiki/N-queens_problem

extern crate test;

use std::vec::Vec;
use std::iter::AdditiveIterator;

#[cfg(test)]
use test::Bencher;

#[cfg(not(test))]
fn main() {
    for num in range(0i32, 16) {
        println!("Sequential: {}: {}", num, n_queens(num));
    }
    for num in range(0i32, 16) {
        println!("Parallel: {}: {}", num, semi_parallel_n_queens(num));
    }
}

/*           _
   ___  ___ | |_   _____ _ __
  / __|/ _ \| \ \ / / _ \ '__/
  \__ \ (_) | |\ V /  __/ |
  |___/\___/|_| \_/ \___|_|

*/

// Solves n-queens using a depth-first, backtracking solution.
// Returns the number of solutions for a given n.
fn n_queens(n: i32) -> uint {
    // Pass off to our helper function.
    return n_queens_helper((1 << n as uint) -1, 0, 0, 0);
}

// The meat of the algorithm is in here, a recursive helper function
// that actually computes the answer using a depth-first, backtracking
// algorithm.
//
// The 30,000 foot overview is as follows:
//
// This function takes only 3 important parameters: three integers
// which represent the spots on the current row that are blocked
// by previous queens.
//
// The "secret sauce" here is that we can avoid passing around the board
// or even the locations of the previous queens and instead we use this
// information to infer the conflicts for the next row.
//
// Once we know the conflicts in our current row we can simply recurse
// over all of the open spots and profit.
//
// This implementation is optimized for speed and memory by using
// integers and bit shifting instead of arrays for storing the conflicts.
fn n_queens_helper(all_ones: i32, left_diags: i32, columns: i32, right_diags: i32) -> uint {
    // all_ones is a special value that simply has all 1s in the first n positions
    // and 0s elsewhere. We can use it to clear out areas that we don't care about.

    // Our solution count.
    // This will be updated by the recursive calls to our helper.
    let mut solutions = 0;

    // We get validSpots with some bit trickery. Effectively, each of the parameters
    // can be ORed together to create an integer with all the conflicts together,
    // which we then invert and limit by ANDing with all_ones, our special value
    //from earlier.
    let mut valid_spots = !(left_diags | columns | right_diags) & all_ones;

    // Since valid_spots contains 1s in all of the locations that
    // are conflict-free, we know we have gone through all of
    // those locations when valid_spots is all 0s, i.e. when it is 0.
    while valid_spots != 0 {
        // This is just bit trickery. For reasons involving the weird
        // behavior of two's complement integers, this creates an integer
        // which is all 0s except for a single 1 in the position of the
        // LSB of valid_spots.
        let spot = -valid_spots & valid_spots;

        // We then XOR that integer with the validSpots to flip it to 0
        // in valid_spots.
        valid_spots = valid_spots ^ spot;

        // Make a recursive call. This is where we infer the conflicts
        // for the next row.
        solutions += n_queens_helper(
            all_ones,
            // We add a conflict in the current spot and then shift left,
            // which has the desired effect of moving all of the conflicts
            // that are created by left diagonals to the left one square.
            (left_diags | spot) << 1,

            // For columns we simply mark this column as filled by ORing
            // in the currentSpot.
            (columns | spot),

            // This is the same as the left_diag shift, except we shift
            // right because these conflicts are caused by right diagonals.
            (right_diags | spot) >> 1);
    }

    // If columns is all blocked (i.e. if it is all ones) then we
    // have arrived at a solution because we have placed n queens.
    solutions + ((columns == all_ones) as uint)
}

// This is the same as the regular nQueens except it creates
// n threads in which to to do the work.
//
// This is much slower for smaller numbers (under 16~17) but outperforms
// the sequential algorithm after that.
fn semi_parallel_n_queens(n: i32) -> uint {
    let all_ones = (1 << n as uint) - 1;
    let (columns, left_diags, right_diags) = (0, 0, 0);

    let mut receivers = Vec::new();
    let mut valid_spots = !(left_diags | columns | right_diags) & all_ones;
    while valid_spots != 0 {
        let (tx, rx) = channel();
        let spot = -valid_spots & valid_spots;
        valid_spots = valid_spots ^ spot;
        receivers.push(rx);

        spawn(proc() {
            tx.send(n_queens_helper(all_ones,
                                    (left_diags | spot) << 1,
                                    (columns | spot),
                                    (right_diags | spot) >> 1));
        });
    }

    receivers.iter().map(|r| r.recv()).sum() + ((columns == all_ones) as uint)
}

// Tests

#[test]
fn test_n_queens() {
    let real = vec!(1, 1, 0, 0, 2, 10, 4, 40, 92u);
    for num in range(0, 9i32) {
        assert_eq!(n_queens(num), real[num as uint]);
    }
}

#[test]
fn test_parallel_n_queens() {
    let real = vec!(1, 1, 0, 0, 2, 10, 4, 40, 92u);
    for num in range(0, 9i32) {
        assert_eq!(semi_parallel_n_queens(num), real[num as uint]);
    }
}

#[bench]
fn bench_n_queens(b: &mut Bencher) {
    b.iter(|| { test::black_box(n_queens(16)); });
}

#[bench]
fn bench_semi_parallel_n_queens(b: &mut Bencher) {
    b.iter(|| { test::black_box(semi_parallel_n_queens(16)); });
}
<|endoftext|>


<commit_before>// Rx -- Reactive programming for Rust
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

pub trait Observer<T, E> {
    /// Provides the observer with new data.
    fn on_next(&mut self, item: T);

    /// Notifies the observer that the provider has finished sending notifications.
    fn on_completed(self);

    /// Notifies the observer that the provider experienced an error condition.
    fn on_error(self, error: E);
}

pub trait PanickingObserver<T> {
    /// Provides the observer with new data.
    fn on_next(&mut self, item: T);

    /// Notifies the observer that the provider has finished sending notifications.
    fn on_completed(self);

    /// Creates an `Observer` out of a `PanickingObserver`.
    ///
    /// An `on_error()` call is handled by panicking.
    fn panic_on_error(self) -> PanickingObserverWrapper<Self> where Self: Sized {
        PanickingObserverWrapper {
            panicking_observer: self
        }
    }
}

pub struct PanickingObserverWrapper<O: Sized> {
    panicking_observer: O
}

impl<T, E, O: PanickingObserver<T>> Observer<T, E> for PanickingObserverWrapper<O> {
    fn on_next(&mut self, item: T) {
        self.panicking_observer.on_next(item);
    }

    fn on_completed(self) {
        self.panicking_observer.on_completed();
    }

    fn on_error(self, error: E) {
        panic!("panicking observer received error");
    }
}

/// Observer implementation for functions.
///
/// Observer behavior translates into a function all as follows:
///
///  * `on_next(item)` calls the function with `Some(Ok(item))`.
///  * `on_completed()` calls the function with `None`.
///    The function will not be called after that.
///  * `on_error(err)` calls the function with `Some(Err(error))`.
///    The function will not be called after that.
impl<F, T, E> Observer<T, E> for F where F: FnMut(Option<Result<T, E>>) {
    fn on_next(&mut self, item: T) {
        self.call_mut((Some(Ok(item)),));
    }

    fn on_completed(self) {
        self.call_once((None,));
    }

    fn on_error(self, error: E) {
        self.call_once((Some(Err(error)),));
    }
}

/// Observer implementation for functions ignoring error handling.
///
/// Observer behavior translates into a function all as follows:
///
///  * `on_next(item)` calls the function with `Some(Ok(item))`.
///  * `on_completed()` calls the function with `None`.
///    The function will not be called after that.
impl<F, T> PanickingObserver<T> for F where F: FnMut(Option<T>) {
    fn on_next(&mut self, item: T) {
        self.call_mut((Some(item),));
    }

    fn on_completed(self) {
        self.call_once((None,));
    }
}
<commit_msg>Make unwrapping observer work with Debug only<commit_after>// Rx -- Reactive programming for Rust
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

use std::fmt::Debug;

pub trait Observer<T, E> {
    /// Provides the observer with new data.
    fn on_next(&mut self, item: T);

    /// Notifies the observer that the provider has finished sending notifications.
    fn on_completed(self);

    /// Notifies the observer that the provider experienced an error condition.
    fn on_error(self, error: E);
}

pub trait PanickingObserver<T> {
    /// Provides the observer with new data.
    fn on_next(&mut self, item: T);

    /// Notifies the observer that the provider has finished sending notifications.
    fn on_completed(self);

    /// Creates an `Observer` out of a `PanickingObserver`.
    ///
    /// An `on_error()` call to the observer is handled by panicking.
    fn unwrap(self) -> UnwrappingObserver<Self> where Self: Sized {
        UnwrappingObserver {
            panicking_observer: self
        }
    }
}

pub struct UnwrappingObserver<PO: Sized> {
    panicking_observer: PO
}

impl<T, E: Debug, PO: PanickingObserver<T>> Observer<T, E> for UnwrappingObserver<PO> {
    fn on_next(&mut self, item: T) {
        self.panicking_observer.on_next(item);
    }

    fn on_completed(self) {
        self.panicking_observer.on_completed();
    }

    fn on_error(self, error: E) {
        panic!("panicking observer received error: {:?}", error);
    }
}

/// Observer implementation for functions.
///
/// Observer behavior translates into a function all as follows:
///
///  * `on_next(item)` calls the function with `Some(Ok(item))`.
///  * `on_completed()` calls the function with `None`.
///    The function will not be called after that.
///  * `on_error(err)` calls the function with `Some(Err(error))`.
///    The function will not be called after that.
impl<F, T, E> Observer<T, E> for F where F: FnMut(Option<Result<T, E>>) {
    fn on_next(&mut self, item: T) {
        self.call_mut((Some(Ok(item)),));
    }

    fn on_completed(self) {
        self.call_once((None,));
    }

    fn on_error(self, error: E) {
        self.call_once((Some(Err(error)),));
    }
}

/// Observer implementation for functions ignoring error handling.
///
/// Observer behavior translates into a function all as follows:
///
///  * `on_next(item)` calls the function with `Some(Ok(item))`.
///  * `on_completed()` calls the function with `None`.
///    The function will not be called after that.
impl<F, T> PanickingObserver<T> for F where F: FnMut(Option<T>) {
    fn on_next(&mut self, item: T) {
        self.call_mut((Some(item),));
    }

    fn on_completed(self) {
        self.call_once((None,));
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod extra;
extern mod rustc;
extern mod rustpkg;

use extra::time;
use rustc::driver::driver::host_triple;
use rustpkg::api;
use std::from_str::{from_str};
use std::io;
use std::option::{Option};
use std::os;
use std::run;
use std::str;
use std::vec;

struct Version {
    major: uint,
    minor: uint
}

impl Version {
    pub fn parse(version_str: &str) -> Option<Version> {
        let mut it = version_str.split_iter('.');
        match (it.next().and_then(from_str::<uint>), it.next().and_then(from_str::<uint>)) {
            (Some(major), Some(minor)) => Some(Version { major: major, minor: minor }),
            _                          => None
        }
    }
}

impl ToStr for Version {
    fn to_str(&self) -> ~str {
        fmt!("%u.%u", self.major, self.minor)
    }
}

impl Ord for Version {
    fn ge(&self, other: &Version) -> bool {
        !self.lt(other)
    }

    fn gt(&self, other: &Version) -> bool {
        self.major > other.major || (self.major == other.major && self.minor > other.minor)
    }

    fn le(&self, other: &Version) -> bool {
        !self.gt(other)
    }

    fn lt(&self, other: &Version) -> bool {
        self.major < other.major || (self.major == other.major && self.minor < other.minor)
    }
}

fn cd(path: &Path) {
    if !os::change_dir(path) {
        fail2!("Package script error: Failed to `cd` into `{}`", path.to_str());
    }
}

fn main() {
    let args = os::args();
    let args_len = args.len();

    if args_len < 2 {
        fail!("Package script requires a directory where rustc libraries live as the first argument");
    } else if args_len < 3 {
        fail!("Package script requires a command as the second argument");
    }

    let sysroot_arg = args[1].clone();
    let sysroot_path = Path(sysroot_arg);

    if args[2] != ~"install" {
        fail2!("Package script error: Unsupported command `{}`", args[2]);
    }

    let pcre_libs = match os::getenv("PCRE_LIBS") {
        None            => {
            let pcre_config_output = run::process_output("pcre-config", [~"--libs"]);
            if pcre_config_output.status != 0 {
                fail!("Package script error: `pcre-config` failed");
            }
            let output_ptr = vec::raw::to_ptr(pcre_config_output.output);
            let output_len = pcre_config_output.output.len();
            let libs_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
            os::setenv("PCRE_LIBS", libs_str);
            libs_str
        },
        Some(pcre_libs) => pcre_libs
    };
    // `pcre-config` adds a newline to the end, which we need to trim away because newlines
    // in link_args cause build issues.
    let trimmed_pcre_libs = pcre_libs.trim();
    debug!("PCRE_LIBS=\"%s\"", trimmed_pcre_libs);

    let workspace_path = os::getcwd();

    // Check the version
    let target_build_path = workspace_path.push("build").push(host_triple());
    if !os::path_exists(&target_build_path) {
        if !os::make_dir(&target_build_path, 0x1FF) {
            fail2!("Package script error: Failed to create target build directory `{}`", target_build_path.to_str());
        }
    }
    let out_path = target_build_path.push("pcre");
    if !os::path_exists(&out_path) {
        if !os::make_dir(&out_path, 0x1FF) {
            fail2!("Package script error: Failed to create output directory `{}`", out_path.to_str());
        }
    }

    let versioncheck_rs_path = out_path.push("versioncheck.rs");
    {
        let w = match io::file_writer(&versioncheck_rs_path, [io::Create]) {
            Err(err_str) => fail2!("Package script error: Failed to open `{}` for writing: {}", versioncheck_rs_path.to_str(), err_str),
            Ok(w)        => w
        };
        w.write_str("\
use std::c_str::{CString};
use std::libc::*;
use std::ptr;
use std::vec;

type options = c_int;
struct pcre;
struct pcre_extra;

#[link_args = \"" + trimmed_pcre_libs + "\"]
extern {
    static pcre_free: extern \"C\" fn(ptr: *c_void);

    fn pcre_compile(pattern: *c_char, options: options, errptr: *mut *c_char, erroffset: *mut c_int, tableptr: *c_uchar) -> *pcre;
    fn pcre_exec(code: *pcre, extra: *pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: options, ovector: *mut c_int, ovecsize: c_int) -> c_int;
    fn pcre_version() -> *c_char;
}

#[fixed_stack_segment]
#[inline(never)]
fn main () {
    unsafe {
        let version_cstring = CString::new(pcre_version(), false);
        let version_str = version_cstring.as_str().unwrap().to_owned();

        let pattern = \"^\\\\d+\\\\.\\\\d+\";
        do pattern.with_c_str |pattern_c_str| {
            let mut err: *c_char = ptr::null();
            let mut erroffset: c_int = 0;
            let code = pcre_compile(pattern_c_str, 0, &mut err, &mut erroffset, ptr::null());
            if ptr::is_null(code) {
                if ptr::is_null(code) {
                    let err_cstring = CString::new(err, false);
                    match err_cstring.as_str() {
                        None          => fail2!(\"pcre_compile() failed at offset {}\", erroffset as uint),
                        Some(err_str) => fail2!(\"pcre_compile() failed at offset {}: {}\", erroffset as uint, err_str)
                    }
                }
            }
            assert!(ptr::is_not_null(code));

            let ovecsize = 1 * 3;
            let mut ovector: ~[c_int] = vec::from_elem(ovecsize, 0 as c_int);
            do version_str.with_c_str_unchecked |version_c_str| {
                let rc = pcre_exec(code, ptr::null(), version_c_str, version_str.len() as c_int, 0, 0, vec::raw::to_mut_ptr(ovector), ovecsize as c_int);
                if rc < 0 {
                    fail!(\"pcre_exec() failed\");
                }

                print(version_str.slice_to(ovector[1] as uint));
            }

            pcre_free(code as *c_void);
        }
    }
}
");
    }

    // Compile and run `versioncheck.rs`
    cd(&out_path);
    let rust_run_output = run::process_output("rust", [~"run", ~"versioncheck.rs"]);
    cd(&workspace_path);
    if rust_run_output.status != 0 {
        fail!("Package script error: `rust run versioncheck.rs` failed");
    }
    let output_ptr = vec::raw::to_ptr(rust_run_output.output);
    let output_len = rust_run_output.output.len();
    let output_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };

    // The "no debug symbols in executable" warning may be present in the output.
    // https://github.com/mozilla/rust/issues/3495
    let mut output_rsplit_iter = output_str.rsplit_iter('\n');
    let version_str: ~str = match output_rsplit_iter.next() {
        None              => output_str.clone(),
        Some(version_str) => version_str.to_owned()
    };

    debug!("libpcre version %s", version_str);

    let min_required_version = Version::parse("8.20").unwrap();
    let pcre_version = match Version::parse(version_str) {
        None               => fail2!("Package script error: Failed to parse version string '{}'", version_str),
        Some(pcre_version) => pcre_version
    };
    if pcre_version < min_required_version {
        fail2!("Package script error: Found libpcre version {}, but at least version {} is required", version_str, min_required_version.to_str());
    }

    let src_path = workspace_path.push("src");

    // Output `src/pcre/detail/native.rs`
    let detail_src_path = src_path.push("pcre").push("detail");
    if !os::path_exists(&detail_src_path) {
        fail2!("Package script error: Source directory `{}` does not exist.", detail_src_path.to_str());
    }
    let native_rs_path = detail_src_path.push("native.rs");
    let native_rs_in_path = detail_src_path.push("native.rs.in");
    if !os::path_exists(&native_rs_in_path) {
        fail2!("Package script error: Source file `{}` does not exist.", native_rs_in_path.to_str());
    }
    {
        let r = match io::file_reader(&native_rs_in_path) {
            Err(err_str) => fail2!("Package script error: Failed to open `{}` for reading: {}", native_rs_in_path.to_str(), err_str),
            Ok(r)        => r
        };
        let w = match io::file_writer(&native_rs_path, [io::Create]) {
            Err(err_str) => fail2!("Package script error: Failed to open `{}` for writing: {}", native_rs_path.to_str(), err_str),
            Ok(w)        => w
        };
        w.write_line("// -*- buffer-read-only: t -*-");
        w.write_line("// Generated by " + args[0] + " on " + time::now().rfc822());
        w.write_char('\n');

        do r.each_line |line| -> bool {
            let substituted_line = str::replace(line, "@PCRE_LIBS@", trimmed_pcre_libs);
            w.write_line(substituted_line);
            true
        };
    }

    api::build_lib(sysroot_path, workspace_path, ~"pcre", rustpkg::version::ExactRevision(~"0.1"), Path("mod.rs"));
}
<commit_msg>Add a no-op "configs" implementation<commit_after>// Copyright 2013 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod extra;
extern mod rustc;
extern mod rustpkg;

use extra::time;
use rustc::driver::driver::host_triple;
use rustpkg::api;
use std::from_str::{from_str};
use std::io;
use std::option::{Option};
use std::os;
use std::run;
use std::str;
use std::util;
use std::vec;

struct Version {
    major: uint,
    minor: uint
}

impl Version {
    pub fn parse(version_str: &str) -> Option<Version> {
        let mut it = version_str.split_iter('.');
        match (it.next().and_then(from_str::<uint>), it.next().and_then(from_str::<uint>)) {
            (Some(major), Some(minor)) => Some(Version { major: major, minor: minor }),
            _                          => None
        }
    }
}

impl ToStr for Version {
    fn to_str(&self) -> ~str {
        fmt!("%u.%u", self.major, self.minor)
    }
}

impl Ord for Version {
    fn ge(&self, other: &Version) -> bool {
        !self.lt(other)
    }

    fn gt(&self, other: &Version) -> bool {
        self.major > other.major || (self.major == other.major && self.minor > other.minor)
    }

    fn le(&self, other: &Version) -> bool {
        !self.gt(other)
    }

    fn lt(&self, other: &Version) -> bool {
        self.major < other.major || (self.major == other.major && self.minor < other.minor)
    }
}

fn cd(path: &Path) {
    if !os::change_dir(path) {
        fail2!("Package script error: Failed to `cd` into `{}`", path.to_str());
    }
}

fn do_install(args: ~[~str]) {
    let sysroot_arg = args[1].clone();
    let sysroot_path = Path(sysroot_arg);

    let pcre_libs = match os::getenv("PCRE_LIBS") {
        None            => {
            let pcre_config_output = run::process_output("pcre-config", [~"--libs"]);
            if pcre_config_output.status != 0 {
                fail!("Package script error: `pcre-config` failed");
            }
            let output_ptr = vec::raw::to_ptr(pcre_config_output.output);
            let output_len = pcre_config_output.output.len();
            let libs_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
            os::setenv("PCRE_LIBS", libs_str);
            libs_str
        },
        Some(pcre_libs) => pcre_libs
    };
    // `pcre-config` adds a newline to the end, which we need to trim away because newlines
    // in link_args cause build issues.
    let trimmed_pcre_libs = pcre_libs.trim();
    debug!("PCRE_LIBS=\"%s\"", trimmed_pcre_libs);

    let workspace_path = os::getcwd();

    // Check the version
    let target_build_path = workspace_path.push("build").push(host_triple());
    if !os::path_exists(&target_build_path) {
        if !os::make_dir(&target_build_path, 0x1FF) {
            fail2!("Package script error: Failed to create target build directory `{}`", target_build_path.to_str());
        }
    }
    let out_path = target_build_path.push("pcre");
    if !os::path_exists(&out_path) {
        if !os::make_dir(&out_path, 0x1FF) {
            fail2!("Package script error: Failed to create output directory `{}`", out_path.to_str());
        }
    }

    let versioncheck_rs_path = out_path.push("versioncheck.rs");
    {
        let w = match io::file_writer(&versioncheck_rs_path, [io::Create]) {
            Err(err_str) => fail2!("Package script error: Failed to open `{}` for writing: {}", versioncheck_rs_path.to_str(), err_str),
            Ok(w)        => w
        };
        w.write_str("\
use std::c_str::{CString};
use std::libc::*;
use std::ptr;
use std::vec;

type options = c_int;
struct pcre;
struct pcre_extra;

#[link_args = \"" + trimmed_pcre_libs + "\"]
extern {
    static pcre_free: extern \"C\" fn(ptr: *c_void);

    fn pcre_compile(pattern: *c_char, options: options, errptr: *mut *c_char, erroffset: *mut c_int, tableptr: *c_uchar) -> *pcre;
    fn pcre_exec(code: *pcre, extra: *pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: options, ovector: *mut c_int, ovecsize: c_int) -> c_int;
    fn pcre_version() -> *c_char;
}

#[fixed_stack_segment]
#[inline(never)]
fn main () {
    unsafe {
        let version_cstring = CString::new(pcre_version(), false);
        let version_str = version_cstring.as_str().unwrap().to_owned();

        let pattern = \"^\\\\d+\\\\.\\\\d+\";
        do pattern.with_c_str |pattern_c_str| {
            let mut err: *c_char = ptr::null();
            let mut erroffset: c_int = 0;
            let code = pcre_compile(pattern_c_str, 0, &mut err, &mut erroffset, ptr::null());
            if ptr::is_null(code) {
                if ptr::is_null(code) {
                    let err_cstring = CString::new(err, false);
                    match err_cstring.as_str() {
                        None          => fail2!(\"pcre_compile() failed at offset {}\", erroffset as uint),
                        Some(err_str) => fail2!(\"pcre_compile() failed at offset {}: {}\", erroffset as uint, err_str)
                    }
                }
            }
            assert!(ptr::is_not_null(code));

            let ovecsize = 1 * 3;
            let mut ovector: ~[c_int] = vec::from_elem(ovecsize, 0 as c_int);
            do version_str.with_c_str_unchecked |version_c_str| {
                let rc = pcre_exec(code, ptr::null(), version_c_str, version_str.len() as c_int, 0, 0, vec::raw::to_mut_ptr(ovector), ovecsize as c_int);
                if rc < 0 {
                    fail!(\"pcre_exec() failed\");
                }

                print(version_str.slice_to(ovector[1] as uint));
            }

            pcre_free(code as *c_void);
        }
    }
}
");
    }

    // Compile and run `versioncheck.rs`
    cd(&out_path);
    let rust_run_output = run::process_output("rust", [~"run", ~"versioncheck.rs"]);
    cd(&workspace_path);
    if rust_run_output.status != 0 {
        fail!("Package script error: `rust run versioncheck.rs` failed");
    }
    let output_ptr = vec::raw::to_ptr(rust_run_output.output);
    let output_len = rust_run_output.output.len();
    let output_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };

    // The "no debug symbols in executable" warning may be present in the output.
    // https://github.com/mozilla/rust/issues/3495
    let mut output_rsplit_iter = output_str.rsplit_iter('\n');
    let version_str: ~str = match output_rsplit_iter.next() {
        None              => output_str.clone(),
        Some(version_str) => version_str.to_owned()
    };

    debug!("libpcre version %s", version_str);

    let min_required_version = Version::parse("8.20").unwrap();
    let pcre_version = match Version::parse(version_str) {
        None               => fail2!("Package script error: Failed to parse version string '{}'", version_str),
        Some(pcre_version) => pcre_version
    };
    if pcre_version < min_required_version {
        fail2!("Package script error: Found libpcre version {}, but at least version {} is required", version_str, min_required_version.to_str());
    }

    let src_path = workspace_path.push("src");

    // Output `src/pcre/detail/native.rs`
    let detail_src_path = src_path.push("pcre").push("detail");
    if !os::path_exists(&detail_src_path) {
        fail2!("Package script error: Source directory `{}` does not exist.", detail_src_path.to_str());
    }
    let native_rs_path = detail_src_path.push("native.rs");
    let native_rs_in_path = detail_src_path.push("native.rs.in");
    if !os::path_exists(&native_rs_in_path) {
        fail2!("Package script error: Source file `{}` does not exist.", native_rs_in_path.to_str());
    }
    {
        let r = match io::file_reader(&native_rs_in_path) {
            Err(err_str) => fail2!("Package script error: Failed to open `{}` for reading: {}", native_rs_in_path.to_str(), err_str),
            Ok(r)        => r
        };
        let w = match io::file_writer(&native_rs_path, [io::Create]) {
            Err(err_str) => fail2!("Package script error: Failed to open `{}` for writing: {}", native_rs_path.to_str(), err_str),
            Ok(w)        => w
        };
        w.write_line("// -*- buffer-read-only: t -*-");
        w.write_line("// Generated by " + args[0] + " on " + time::now().rfc822());
        w.write_char('\n');

        do r.each_line |line| -> bool {
            let substituted_line = str::replace(line, "@PCRE_LIBS@", trimmed_pcre_libs);
            w.write_line(substituted_line);
            true
        };
    }

    api::build_lib(sysroot_path, workspace_path, ~"pcre", rustpkg::version::ExactRevision(~"0.1"), Path("mod.rs"));
}

fn do_configs(args: ~[~str]) {
    util::ignore(args);
}

fn main() {
    let args = os::args();
    let args_len = args.len();

    if args_len < 2 {
        fail!("Package script requires a directory where rustc libraries live as the first argument");
    } else if args_len < 3 {
        fail!("Package script requires a command as the second argument");
    }

    if args[2] == ~"install" {
        do_install(args);
    } else if args[2] == ~"configs" {
        do_configs(args);
    } else {
        fail2!("Package script error: Unsupported command `{}`", args[2]);
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This crate implements the [xoshiro] family of pseudorandom number generators
//! designed by David Blackman and Sebastiano Vigna. They feature high
//! perfomance and a small state and superseed the previous xorshift-based
//! generators. However, they are no cryptographically secure and their output
//! can be predicted by observing a few samples.
//!
//! The following generators are implemented:
//!
//! # 64-bit generators
//! - [`Xoshiro256StarStar`]: Recommended for all purposes. Excellent speed and
//!   a state space (256 bits) large enough for any parallel application.
//! - [`Xoshiro256PlusPlus`]: Recommended for all purposes. Excellent speed and
//!   a state space (256 bits) large enough for any parallel application.
//! - [`Xoshiro256Plus`]: Recommended for generating 64-bit floating-point
//!   numbers. About 15% faster than `Xoshiro256StarStar`, but has a [low linear
//!   complexity] in the lowest bits (which are discarded when generating
//!   floats), making it fail linearity tests. This is unlikely to have any
//!   impact in practise.
//! - [`Xoroshiro128StarStar`]: An alternative to `Xoshiro256StarStar`, having
//!   the same speed but using half the state. Only suited for low-scale parallel
//!   applications.
//! - [`Xoroshiro128PlusPlus`]: An alternative to `Xoshiro256PlusPlus`, having
//!   the same speed but using half the state. Only suited for low-scale parallel
//!   applications.
//! - [`Xoroshiro128Plus`]: An alternative to `Xoshiro256Plus`, having the same
//!   speed but using half the state. Only suited for low-scale parallel
//!   applications. Has a [low linear complexity] in the lowest bits (which are
//!   discarded when generating floats), making it fail linearity tests. This is
//!   unlikely to have any impact in practise.
//! - [`Xoshiro512StarStar`]: An alternative to `Xoshiro256StarStar` with more
//!   state and the same speed.
//! - [`Xoshiro512PlusPlus`]: An alternative to `Xoshiro256PlusPlus` with more
//!   state and the same speed.
//! - [`Xoshiro512Plus`]: An alternative to `Xoshiro512Plus` with more
//!   state and the same speed. Has a [low linear complexity] in the lowest bits
//!   (which are discarded when generating floats), making it fail linearity
//!   tests. This is unlikely to have any impact in practise.
//! - [`SplitMix64`]: Recommended for initializing generators of the xoshiro
//!   familiy from a 64-bit seed. Used for implementing `seed_from_u64`.
//!
//! # 32-bit generators
//! - [`Xoshiro128StarStar`]: Recommended for all purposes. Excellent speed.
//! - [`Xoshiro128PlusPlus`]: Recommended for all purposes. Excellent speed.
//! - [`Xoshiro128Plus`]: Recommended for generating 32-bit floating-point
//!   numbers. Faster than `Xoshiro128StarStar`, but has a [low linear
//!   complexity] in the lowest bits (which are discarded when generating
//!   floats), making it fail linearity tests. This is unlikely to have any
//!   impact in practise.
//! - [`Xoroshiro64StarStar`]: An alternative to `Xoshiro128StarStar`, having
//!   the same speed but using half the state.
//! - [`Xoroshiro64Star`]: An alternative to `Xoshiro128Plus`, having the
//!   same speed but using half the state. Has a [low linear complexity] in the
//!   lowest bits (which are discarded when generating floats), making it fail
//!   linearity tests. This is unlikely to have any impact in practise.
//!
//! [xoshiro]: http://xoshiro.di.unimi.it/
//! [low linear complexity]: http://xoshiro.di.unimi.it/lowcomp.php

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
       html_favicon_url = "https://www.rust-lang.org/favicon.ico",
       html_root_url = "https://docs.rs/rand_xoshiro/0.3.1")]

#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![allow(clippy::unreadable_literal)]
#![no_std]

#[macro_use]
mod common;
mod splitmix64;
mod xoshiro128starstar;
mod xoshiro128plusplus;
mod xoshiro128plus;
mod xoshiro256starstar;
mod xoshiro256plusplus;
mod xoshiro256plus;
mod xoshiro512starstar;
mod xoshiro512plusplus;
mod xoshiro512plus;
mod xoroshiro128plus;
mod xoroshiro128plusplus;
mod xoroshiro128starstar;
mod xoroshiro64starstar;
mod xoroshiro64star;

pub use rand_core;
pub use splitmix64::SplitMix64;
pub use xoshiro128starstar::Xoshiro128StarStar;
pub use xoshiro128plusplus::Xoshiro128PlusPlus;
pub use xoshiro128plus::Xoshiro128Plus;
pub use xoshiro256starstar::Xoshiro256StarStar;
pub use xoshiro256plusplus::Xoshiro256PlusPlus;
pub use xoshiro256plus::Xoshiro256Plus;
pub use common::Seed512;
pub use xoshiro512starstar::Xoshiro512StarStar;
pub use xoshiro512plusplus::Xoshiro512PlusPlus;
pub use xoshiro512plus::Xoshiro512Plus;
pub use xoroshiro128plus::Xoroshiro128Plus;
pub use xoroshiro128starstar::Xoroshiro128StarStar;
pub use xoroshiro128plusplus::Xoroshiro128PlusPlus;
pub use xoroshiro64starstar::Xoroshiro64StarStar;
pub use xoroshiro64star::Xoroshiro64Star;
<commit_msg>rand_xoshiro: Refer to `*StarStar` and `*PlusPlus` differences<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This crate implements the [xoshiro] family of pseudorandom number generators
//! designed by David Blackman and Sebastiano Vigna. They feature high
//! perfomance and a small state and superseed the previous xorshift-based
//! generators. However, they are no cryptographically secure and their output
//! can be predicted by observing a few samples.
//!
//! The following generators are implemented:
//!
//! # 64-bit generators
//! - [`Xoshiro256StarStar`]: Recommended for all purposes. Excellent speed and
//!   a state space (256 bits) large enough for any parallel application.
//! - [`Xoshiro256PlusPlus`]: Recommended for all purposes. Excellent speed and
//!   a state space (256 bits) large enough for any parallel application.
//! - [`Xoshiro256Plus`]: Recommended for generating 64-bit floating-point
//!   numbers. About 15% faster than `Xoshiro256StarStar`, but has a [low linear
//!   complexity] in the lowest bits (which are discarded when generating
//!   floats), making it fail linearity tests. This is unlikely to have any
//!   impact in practise.
//! - [`Xoroshiro128StarStar`]: An alternative to `Xoshiro256StarStar`, having
//!   the same speed but using half the state. Only suited for low-scale parallel
//!   applications.
//! - [`Xoroshiro128PlusPlus`]: An alternative to `Xoshiro256PlusPlus`, having
//!   the same speed but using half the state. Only suited for low-scale parallel
//!   applications.
//! - [`Xoroshiro128Plus`]: An alternative to `Xoshiro256Plus`, having the same
//!   speed but using half the state. Only suited for low-scale parallel
//!   applications. Has a [low linear complexity] in the lowest bits (which are
//!   discarded when generating floats), making it fail linearity tests. This is
//!   unlikely to have any impact in practise.
//! - [`Xoshiro512StarStar`]: An alternative to `Xoshiro256StarStar` with more
//!   state and the same speed.
//! - [`Xoshiro512PlusPlus`]: An alternative to `Xoshiro256PlusPlus` with more
//!   state and the same speed.
//! - [`Xoshiro512Plus`]: An alternative to `Xoshiro512Plus` with more
//!   state and the same speed. Has a [low linear complexity] in the lowest bits
//!   (which are discarded when generating floats), making it fail linearity
//!   tests. This is unlikely to have any impact in practise.
//! - [`SplitMix64`]: Recommended for initializing generators of the xoshiro
//!   familiy from a 64-bit seed. Used for implementing `seed_from_u64`.
//!
//! # 32-bit generators
//! - [`Xoshiro128StarStar`]: Recommended for all purposes. Excellent speed.
//! - [`Xoshiro128PlusPlus`]: Recommended for all purposes. Excellent speed.
//! - [`Xoshiro128Plus`]: Recommended for generating 32-bit floating-point
//!   numbers. Faster than `Xoshiro128StarStar`, but has a [low linear
//!   complexity] in the lowest bits (which are discarded when generating
//!   floats), making it fail linearity tests. This is unlikely to have any
//!   impact in practise.
//! - [`Xoroshiro64StarStar`]: An alternative to `Xoshiro128StarStar`, having
//!   the same speed but using half the state.
//! - [`Xoroshiro64Star`]: An alternative to `Xoshiro128Plus`, having the
//!   same speed but using half the state. Has a [low linear complexity] in the
//!   lowest bits (which are discarded when generating floats), making it fail
//!   linearity tests. This is unlikely to have any impact in practise.
//!
//! The `*PlusPlus` generators perform similarily to the `*StarStar` generators.
//! See the [xoshiro paper], where the differences are discussed in detail.
//!
//! [xoshiro]: http://xoshiro.di.unimi.it/
//! [xoshiro paper]: http://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf
//! [low linear complexity]: http://xoshiro.di.unimi.it/lowcomp.php

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
       html_favicon_url = "https://www.rust-lang.org/favicon.ico",
       html_root_url = "https://docs.rs/rand_xoshiro/0.3.1")]

#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![allow(clippy::unreadable_literal)]
#![no_std]

#[macro_use]
mod common;
mod splitmix64;
mod xoshiro128starstar;
mod xoshiro128plusplus;
mod xoshiro128plus;
mod xoshiro256starstar;
mod xoshiro256plusplus;
mod xoshiro256plus;
mod xoshiro512starstar;
mod xoshiro512plusplus;
mod xoshiro512plus;
mod xoroshiro128plus;
mod xoroshiro128plusplus;
mod xoroshiro128starstar;
mod xoroshiro64starstar;
mod xoroshiro64star;

pub use rand_core;
pub use splitmix64::SplitMix64;
pub use xoshiro128starstar::Xoshiro128StarStar;
pub use xoshiro128plusplus::Xoshiro128PlusPlus;
pub use xoshiro128plus::Xoshiro128Plus;
pub use xoshiro256starstar::Xoshiro256StarStar;
pub use xoshiro256plusplus::Xoshiro256PlusPlus;
pub use xoshiro256plus::Xoshiro256Plus;
pub use common::Seed512;
pub use xoshiro512starstar::Xoshiro512StarStar;
pub use xoshiro512plusplus::Xoshiro512PlusPlus;
pub use xoshiro512plus::Xoshiro512Plus;
pub use xoroshiro128plus::Xoroshiro128Plus;
pub use xoroshiro128starstar::Xoroshiro128StarStar;
pub use xoroshiro128plusplus::Xoroshiro128PlusPlus;
pub use xoroshiro64starstar::Xoroshiro64StarStar;
pub use xoroshiro64star::Xoroshiro64Star;
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::prelude::*;
use std::io;
use std::fs::File;
use std::path::Path;

#[cfg(not(feature = "serde_type"))]
use serialize::json::ToJson;
#[cfg(feature = "serde_type")]
use serde::ser::Serialize as ToJson;

use template::{Template};
use render::{Renderable, RenderError, RenderContext};
use helpers::{HelperDef};
use context::{Context};
use helpers;
use support::str::StringWriter;
use error::{TemplateError, TemplateFileError};

/// This type represents an *escape fn*, that is a function who's purpose it is
/// to escape potentially problematic characters in a string.
///
/// The default *escape fn* replaces the characters `&"<>`
/// with the equivalent html / xml entities.
///
/// An *escape fn* is represented as a `Box` to avoid unnecessary type
/// parameters (and because traits cannot be aliased using `type`).
pub type EscapeFn = Box<Fn(&str) -> String + Send + Sync>;

fn get_default_escape_fn() -> EscapeFn {
    Box::new(|data| {
        data.replace("&", "&")
            .replace("\"", """)
            .replace("<", "<")
            .replace(">", ">")
    })
}

fn load_template_from_file (path: &Path) -> io::Result<String> {
    let mut file = try!(File::open(path));
    let mut s = String::new();
    try!(file.read_to_string(&mut s));
    Ok(s)
}

pub struct Registry {
    templates: HashMap<String, Template>,
    helpers: HashMap<String, Box<HelperDef + 'static>>,
    escape_fn: EscapeFn
}

impl Registry {
    pub fn new() -> Registry {
        let mut r = Registry {
            templates: HashMap::new(),
            helpers: HashMap::new(),
            escape_fn: get_default_escape_fn(),
        };

        r.register_helper("if", Box::new(helpers::IF_HELPER));
        r.register_helper("unless", Box::new(helpers::UNLESS_HELPER));
        r.register_helper("each", Box::new(helpers::EACH_HELPER));
        r.register_helper("with", Box::new(helpers::WITH_HELPER));
        r.register_helper("lookup", Box::new(helpers::LOOKUP_HELPER));
        r.register_helper("raw", Box::new(helpers::RAW_HELPER));
        r.register_helper(">", Box::new(helpers::INCLUDE_HELPER));
        r.register_helper("block", Box::new(helpers::BLOCK_HELPER));
        r.register_helper("partial", Box::new(helpers::PARTIAL_HELPER));
        r.register_helper("log", Box::new(helpers::LOG_HELPER));

        r
    }

    pub fn register_template(&mut self, name: &str, mut template: Template) {
        template.name = Some(name.to_owned());
        self.templates.insert(name.to_string(), template);
    }

    pub fn register_template_string(&mut self, name: &str, tpl_str: String) -> Result<(), TemplateError> {
        try!(Template::compile_with_name(tpl_str, name.to_owned())
             .and_then(|t| Ok(self.templates.insert(name.to_string(), t))));
        Ok(())
    }

    pub fn register_template_file(&mut self, name: &str, tpl_path: &Path) -> Result<(), TemplateFileError> {
        load_template_from_file(tpl_path)
            .map_err(TemplateFileError::from)
            .and_then(|s| self.register_template_string(name, s)
                      .map_err(TemplateFileError::from))
    }

    pub fn unregister_template(&mut self, name: &str) {
        self.templates.remove(name);
    }

    pub fn register_helper(&mut self, name: &str, def: Box<HelperDef + 'static>) -> Option<Box<HelperDef + 'static>> {
        self.helpers.insert(name.to_string(), def)
    }

    /// Register a new *escape fn* to be used from now on by this registry.
    pub fn register_escape_fn<F: 'static + Fn(&str) -> String + Send + Sync>(&mut self, escape_fn: F) {
        self.escape_fn = Box::new(escape_fn);
    }

    /// Restore the default *escape fn*.
    pub fn unregister_escape_fn(&mut self) {
        self.escape_fn = get_default_escape_fn();
    }

    /// Get a reference to the current *escape fn*.
    pub fn get_escape_fn(&self) -> &Fn(&str) -> String {
        &*self.escape_fn
    }

    pub fn get_template(&self, name: &str) -> Option<&Template> {
        self.templates.get(name)
    }

    pub fn get_helper(&self, name: &str) -> Option<&Box<HelperDef + 'static>> {
        self.helpers.get(name)
    }

    pub fn get_templates(&self) -> &HashMap<String, Template> {
        &self.templates
    }

    pub fn clear_templates(&mut self) {
        self.templates.clear();
    }

    pub fn render<T>(&self, name: &str, ctx: &T) -> Result<String, RenderError> where T: ToJson {
        let mut writer = StringWriter::new();
        let context = Context::wraps(ctx);
        {
            try!(self.renderw(name, &context, &mut writer));
        }
        Ok(writer.to_string())
    }

    pub fn renderw(&self, name: &str, context: &Context, writer: &mut Write) -> Result<(), RenderError> {
        let template = self.get_template(&name.to_string());

        if let Some(t) = template {
            let mut render_context = RenderContext::new(writer);
            render_context.root_template = t.name.clone();
            (*t).render(context, self, &mut render_context)
        } else {
            Err(RenderError::new(format!("Template not found: {}", name)))
        }
    }
}

#[cfg(test)]
mod test {
    use template::{Template};
    use registry::{Registry};
    use render::{RenderContext, Renderable, RenderError, Helper};
    use helpers::{HelperDef};
    use context::{Context};
    use support::str::StringWriter;

    #[derive(Clone, Copy)]
    struct DummyHelper;

    impl HelperDef for DummyHelper {
        fn call(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<(), RenderError> {
            try!(h.template().unwrap().render(c, r, rc));
            Ok(())
        }
    }

    static DUMMY_HELPER: DummyHelper = DummyHelper;

    #[test]
    fn test_registry_operations() {
        let mut r = Registry::new();

        let t = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index", t.clone());

        let t2 = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index2", t2.clone());

        assert_eq!((*r.get_template(&("index".to_string())).unwrap()).to_string(),
                   t.to_string());
        assert_eq!(r.templates.len(), 2);

        r.unregister_template(&("index".to_string()));
        assert_eq!(r.templates.len(), 1);

        r.clear_templates();
        assert_eq!(r.templates.len(), 0);

        r.register_helper("dummy", Box::new(DUMMY_HELPER));

        // built-in helpers plus 1
        assert_eq!(r.helpers.len(), 10+1);
    }

    #[test]
    fn test_renderw() {
        let mut r = Registry::new();

        let t = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index", t.clone());

        let mut sw = StringWriter::new();
        let context = Context::null();

        {
            r.renderw("index", &context, &mut sw).ok().unwrap();
        }

        assert_eq!("

".to_string(), sw.to_string());

    }

    #[test]
    fn test_escape_fn() {
        let mut r = Registry::new();

        let input = String::from("\"<>&");

        r.register_template_string("test", String::from("{{this}}")).unwrap();

        assert_eq!(""<>&", r.render("test", &input).unwrap());

        r.register_escape_fn(|s| s.into());

        assert_eq!("\"<>&", r.render("test", &input).unwrap());

        r.unregister_escape_fn();

        assert_eq!(""<>&", r.render("test", &input).unwrap());
    }
}
<commit_msg>(feat) added function to load template from `std::io::Read`<commit_after>use std::collections::HashMap;
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;

#[cfg(not(feature = "serde_type"))]
use serialize::json::ToJson;
#[cfg(feature = "serde_type")]
use serde::ser::Serialize as ToJson;

use template::{Template};
use render::{Renderable, RenderError, RenderContext};
use helpers::{HelperDef};
use context::{Context};
use helpers;
use support::str::StringWriter;
use error::{TemplateError, TemplateFileError};

/// This type represents an *escape fn*, that is a function who's purpose it is
/// to escape potentially problematic characters in a string.
///
/// The default *escape fn* replaces the characters `&"<>`
/// with the equivalent html / xml entities.
///
/// An *escape fn* is represented as a `Box` to avoid unnecessary type
/// parameters (and because traits cannot be aliased using `type`).
pub type EscapeFn = Box<Fn(&str) -> String + Send + Sync>;

fn get_default_escape_fn() -> EscapeFn {
    Box::new(|data| {
        data.replace("&", "&")
            .replace("\"", """)
            .replace("<", "<")
            .replace(">", ">")
    })
}

/// The single entry point of your Handlebars templates
///
/// It maintains compiled templates and registered helpers.
pub struct Registry {
    templates: HashMap<String, Template>,
    helpers: HashMap<String, Box<HelperDef + 'static>>,
    escape_fn: EscapeFn
}

impl Registry {
    pub fn new() -> Registry {
        let mut r = Registry {
            templates: HashMap::new(),
            helpers: HashMap::new(),
            escape_fn: get_default_escape_fn(),
        };

        r.register_helper("if", Box::new(helpers::IF_HELPER));
        r.register_helper("unless", Box::new(helpers::UNLESS_HELPER));
        r.register_helper("each", Box::new(helpers::EACH_HELPER));
        r.register_helper("with", Box::new(helpers::WITH_HELPER));
        r.register_helper("lookup", Box::new(helpers::LOOKUP_HELPER));
        r.register_helper("raw", Box::new(helpers::RAW_HELPER));
        r.register_helper(">", Box::new(helpers::INCLUDE_HELPER));
        r.register_helper("block", Box::new(helpers::BLOCK_HELPER));
        r.register_helper("partial", Box::new(helpers::PARTIAL_HELPER));
        r.register_helper("log", Box::new(helpers::LOG_HELPER));

        r
    }

    /// Register a template
    pub fn register_template(&mut self, name: &str, mut template: Template) {
        template.name = Some(name.to_owned());
        self.templates.insert(name.to_string(), template);
    }

    /// Register a template string
    pub fn register_template_string(&mut self, name: &str, tpl_str: String) -> Result<(), TemplateError> {
        try!(Template::compile_with_name(tpl_str, name.to_owned())
             .and_then(|t| Ok(self.templates.insert(name.to_string(), t))));
        Ok(())
    }

    /// Register a template from a path
    pub fn register_template_file(&mut self, name: &str, tpl_path: &Path) -> Result<(), TemplateFileError> {
        let mut file = try!(File::open(tpl_path));
        self.register_template_source(name, &mut file)
    }

    /// Register a template from `std::io::Read` source
    pub fn register_template_source(&mut self, name: &str, tpl_source: &mut Read) -> Result<(), TemplateFileError> {
        let mut buf = String::new();
        try!(tpl_source.read_to_string(&mut buf));
        try!(Template::compile_with_name(&buf, name.to_owned())
             .and_then(|t| Ok(self.templates.insert(name.to_string(), t))));
        Ok(())
    }

    /// remove a template from the registry
    pub fn unregister_template(&mut self, name: &str) {
        self.templates.remove(name);
    }

    /// register a helper
    pub fn register_helper(&mut self, name: &str, def: Box<HelperDef + 'static>) -> Option<Box<HelperDef + 'static>> {
        self.helpers.insert(name.to_string(), def)
    }

    /// Register a new *escape fn* to be used from now on by this registry.
    pub fn register_escape_fn<F: 'static + Fn(&str) -> String + Send + Sync>(&mut self, escape_fn: F) {
        self.escape_fn = Box::new(escape_fn);
    }

    /// Restore the default *escape fn*.
    pub fn unregister_escape_fn(&mut self) {
        self.escape_fn = get_default_escape_fn();
    }

    /// Get a reference to the current *escape fn*.
    pub fn get_escape_fn(&self) -> &Fn(&str) -> String {
        &*self.escape_fn
    }

    /// Return a registered template,
    pub fn get_template(&self, name: &str) -> Option<&Template> {
        self.templates.get(name)
    }

    /// Return a registered helper
    pub fn get_helper(&self, name: &str) -> Option<&Box<HelperDef + 'static>> {
        self.helpers.get(name)
    }

    /// Return all templates registered
    pub fn get_templates(&self) -> &HashMap<String, Template> {
        &self.templates
    }

    /// Unregister all templates
    pub fn clear_templates(&mut self) {
        self.templates.clear();
    }

    /// Render a registered template with some data into a string
    pub fn render<T>(&self, name: &str, ctx: &T) -> Result<String, RenderError> where T: ToJson {
        let mut writer = StringWriter::new();
        let context = Context::wraps(ctx);
        {
            try!(self.renderw(name, &context, &mut writer));
        }
        Ok(writer.to_string())
    }

    /// Render a registered template with some data to the `std::io::Write`
    pub fn renderw(&self, name: &str, context: &Context, writer: &mut Write) -> Result<(), RenderError> {
        let template = self.get_template(&name.to_string());

        if let Some(t) = template {
            let mut render_context = RenderContext::new(writer);
            render_context.root_template = t.name.clone();
            (*t).render(context, self, &mut render_context)
        } else {
            Err(RenderError::new(format!("Template not found: {}", name)))
        }
    }
}

#[cfg(test)]
mod test {
    use template::{Template};
    use registry::{Registry};
    use render::{RenderContext, Renderable, RenderError, Helper};
    use helpers::{HelperDef};
    use context::{Context};
    use support::str::StringWriter;

    #[derive(Clone, Copy)]
    struct DummyHelper;

    impl HelperDef for DummyHelper {
        fn call(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<(), RenderError> {
            try!(h.template().unwrap().render(c, r, rc));
            Ok(())
        }
    }

    static DUMMY_HELPER: DummyHelper = DummyHelper;

    #[test]
    fn test_registry_operations() {
        let mut r = Registry::new();

        let t = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index", t.clone());

        let t2 = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index2", t2.clone());

        assert_eq!((*r.get_template(&("index".to_string())).unwrap()).to_string(),
                   t.to_string());
        assert_eq!(r.templates.len(), 2);

        r.unregister_template(&("index".to_string()));
        assert_eq!(r.templates.len(), 1);

        r.clear_templates();
        assert_eq!(r.templates.len(), 0);

        r.register_helper("dummy", Box::new(DUMMY_HELPER));

        // built-in helpers plus 1
        assert_eq!(r.helpers.len(), 10+1);
    }

    #[test]
    fn test_renderw() {
        let mut r = Registry::new();

        let t = Template::compile("

".to_string()).ok().unwrap();
        r.register_template("index", t.clone());

        let mut sw = StringWriter::new();
        let context = Context::null();

        {
            r.renderw("index", &context, &mut sw).ok().unwrap();
        }

        assert_eq!("

".to_string(), sw.to_string());

    }

    #[test]
    fn test_escape_fn() {
        let mut r = Registry::new();

        let input = String::from("\"<>&");

        r.register_template_string("test", String::from("{{this}}")).unwrap();

        assert_eq!(""<>&", r.render("test", &input).unwrap());

        r.register_escape_fn(|s| s.into());

        assert_eq!("\"<>&", r.render("test", &input).unwrap());

        r.unregister_escape_fn();

        assert_eq!(""<>&", r.render("test", &input).unwrap());
    }
}
<|endoftext|>


<commit_before>use color::Color;
use scene::Scene;
use camera::Camera;
use ray::Ray;
use intersection::Intersection;
use material::Material;
use math::EPSILON;

use rayon::prelude::*;
use std::ops::Range;

pub enum SuperSampling {
    Off,
    On(u32),
}

pub struct Renderer<'a> {
    scene: &'a Scene<'a>,
    camera: &'a Camera,
    super_sampling: SuperSampling,
}

unsafe impl<'a> Sync for Renderer<'a> {}
unsafe impl<'a> Send for Renderer<'a> {}

impl<'a> Renderer<'a> {
    pub fn new(scene: &'a Scene<'a>,
               camera: &'a Camera,
               super_sampling: SuperSampling)
               -> Renderer<'a> {

        Renderer {
            scene: scene,
            camera: camera,
            super_sampling: super_sampling,
        }
    }

    pub fn render(&self, max_depth: u32) -> Vec<u8> {
            let range: Range<usize> = (0 as usize)..(self.camera.height as usize);
            self.render_segment(0, &range, max_depth)
    }

    fn render_segment(&self,
                      segment_offset: usize,
                      segment_range: &Range<usize>,
                      max_depth: u32)
                      -> Vec<u8> {
        let width = self.camera.width as usize;

        segment_range.clone().into_par_iter().flat_map(|y| {
            (0..width).flat_map(move|x| {
                self.render_point(segment_offset, max_depth, x, y).into_iter()
            }).collect::<Vec<u8>>().into_par_iter()
        }).collect::<Vec<u8>>()
    }

    fn render_point(&self, segment_offset: usize, max_depth: u32, x: usize, y:usize) -> Color {
        let samples = match self.super_sampling {
            SuperSampling::Off => 1,
            SuperSampling::On(samples) => samples,
        };

        let mut sample_colors = vec![Color::black(); (samples * samples) as usize];
        let global_y = segment_offset + y;

        for x_sample in 0..samples {
            for y_sample in 0..samples {
                let ray = self.camera.create_ray(x as u32,
                                                 self.camera.height - global_y as u32,
                                                 x_sample,
                                                 y_sample,
                                                 samples);
                sample_colors[(y_sample * samples + x_sample) as usize] =
                    self.trace(ray, max_depth);
            }
        }

        let mut sum_r: f64 = 0.0;
        let mut sum_g: f64 = 0.0;
        let mut sum_b: f64 = 0.0;

        for color in &sample_colors {
            sum_r += color.r_f64();
            sum_g += color.g_f64();
            sum_b += color.b_f64();
        }

        Color::new_f64(sum_r / sample_colors.len() as f64,
                       sum_g / sample_colors.len() as f64,
                       sum_b / sample_colors.len() as f64)
    }

    fn trace(&self, ray: Ray, depth: u32) -> Color {
        if depth == 0 {
            return Color::black();
        }

        let mut result = self.scene.clear_color;
        let possible_hit = self.scene.intersect(ray);

        if let Some(hit) = possible_hit {
            result = self.shade(&hit, ray);

            if hit.shape.material().is_reflective() {
                result = result + self.reflect(&hit, ray, depth);
            }

            if hit.shape.material().is_refractive() {
                result = result + self.refract(&hit, ray, depth);
            }
        }

        result
    }

    fn shade(&self, intersection: &Intersection, original_ray: Ray) -> Color {
        let material: &Material = intersection.shape.material();
        let mut result = material.ambient_color;

        for light in self.scene.lights {
            let mut in_shadow = false;
            let distance_to_light = (intersection.point - light.origin).length();
            let light_direction = (light.origin - intersection.point).normalize();
            let ray = Ray::new(intersection.point + light_direction * EPSILON,
                               light_direction,
                               Some(original_ray.medium_refraction));

            for object in self.scene.objects {
                if let Some(hit) = object.intersect(ray) {
                    if hit.t < distance_to_light {
                        in_shadow = true;
                        break;
                    }
                }
            }

            if in_shadow {
                continue;
            }

            let light_color = light.color();
            let mut dot = light_direction.dot(&intersection.normal);

            // Diffuse
            if dot > 0.0 {
                result = result + (light_color * material.diffuse_color) * dot;
            }

            dot = original_ray.direction.dot(&light_direction.reflect(&intersection.normal));

            // Specular
            if dot > 0.0 {
                let spec = dot.powf(20.0);

                result = result + (light_color * material.specular_color) * spec;
            }
        }

        result
    }

    fn reflect(&self, intersection: &Intersection, original_ray: Ray, current_depth: u32) -> Color {
        let new_direction = original_ray.direction.reflect(&intersection.normal).normalize();

        let new_ray = Ray::new(intersection.point + new_direction * EPSILON,
                               new_direction,
                               Some(original_ray.medium_refraction));

        let reflected_color = self.trace(new_ray, current_depth - 1);

        reflected_color *
        intersection.shape
            .material()
            .reflection_coefficient
            .unwrap_or(0.0)
    }

    fn refract(&self, intersection: &Intersection, original_ray: Ray, current_depth: u32) -> Color {
        assert!(intersection.shape
                    .material()
                    .refraction_coefficient
                    .is_some(),
                "Don't call refract for materials that aren't refractive");
        let mut refraction_coefficient = intersection.shape
            .material()
            .refraction_coefficient
            .unwrap_or(1.0);

        if intersection.inside {
            // Leaving refractive material
            refraction_coefficient = 1.0;
        }

        let n = original_ray.medium_refraction / refraction_coefficient;
        let normal = match intersection.inside {
            true => -intersection.normal,
            false => intersection.normal,
        };

        let cos_i = normal.dot(&original_ray.direction);
        let c2 = 1.0 - n * (1.0 - cos_i * cos_i);

        if c2 > 0.0 {
            let t = (original_ray.direction * n + normal * (n * cos_i - c2.sqrt())).normalize();

            let new_ray = Ray::new(intersection.point + t * EPSILON,
                                   t,
                                   Some(refraction_coefficient));

            let refraction_color = self.trace(new_ray, current_depth - 1);
            let absorbance = intersection.shape.material().ambient_color * 0.15 * -intersection.t;
            let transparency = Color::new_f64(absorbance.r_f64().exp(),
                                              absorbance.g_f64().exp(),
                                              absorbance.b_f64().exp());

            return refraction_color * transparency;

        }

        return Color::black();
    }
}
<commit_msg>Clearify variable naming<commit_after>use color::Color;
use scene::Scene;
use camera::Camera;
use ray::Ray;
use intersection::Intersection;
use material::Material;
use math::EPSILON;

use rayon::prelude::*;
use std::ops::Range;

pub enum SuperSampling {
    Off,
    On(u32),
}

pub struct Renderer<'a> {
    scene: &'a Scene<'a>,
    camera: &'a Camera,
    super_sampling: SuperSampling,
}

unsafe impl<'a> Sync for Renderer<'a> {}
unsafe impl<'a> Send for Renderer<'a> {}

impl<'a> Renderer<'a> {
    pub fn new(scene: &'a Scene<'a>,
               camera: &'a Camera,
               super_sampling: SuperSampling)
               -> Renderer<'a> {

        Renderer {
            scene: scene,
            camera: camera,
            super_sampling: super_sampling,
        }
    }

    pub fn render(&self, max_depth: u32) -> Vec<u8> {
            let range: Range<usize> = (0 as usize)..(self.camera.height as usize);
            self.render_segment(0, &range, max_depth)
    }

    fn render_segment(&self,
                      segment_offset: usize,
                      segment_range: &Range<usize>,
                      max_depth: u32)
                      -> Vec<u8> {
        let width = self.camera.width as usize;

        segment_range.clone().into_par_iter().flat_map(|y| {
            (0..width).flat_map(move|x| {
                self.render_point(segment_offset, max_depth, x, y).into_iter()
            }).collect::<Vec<u8>>().into_par_iter()
        }).collect::<Vec<u8>>()
    }

    fn render_point(&self, segment_offset: usize, max_depth: u32, x: usize, y:usize) -> Color {
        let samples = match self.super_sampling {
            SuperSampling::Off => 1,
            SuperSampling::On(samples) => samples,
        };

        let mut sample_colors = vec![Color::black(); (samples * samples) as usize];
        let global_y = segment_offset + y;

        for x_sample in 0..samples {
            for y_sample in 0..samples {
                let ray = self.camera.create_ray(x as u32,
                                                 self.camera.height - global_y as u32,
                                                 x_sample,
                                                 y_sample,
                                                 samples);
                sample_colors[(y_sample * samples + x_sample) as usize] =
                    self.trace(ray, max_depth);
            }
        }

        let mut sum_r: f64 = 0.0;
        let mut sum_g: f64 = 0.0;
        let mut sum_b: f64 = 0.0;

        for color in &sample_colors {
            sum_r += color.r_f64();
            sum_g += color.g_f64();
            sum_b += color.b_f64();
        }

        Color::new_f64(sum_r / sample_colors.len() as f64,
                       sum_g / sample_colors.len() as f64,
                       sum_b / sample_colors.len() as f64)
    }

    fn trace(&self, ray: Ray, depth: u32) -> Color {
        if depth == 0 {
            return Color::black();
        }

        let mut result = self.scene.clear_color;
        let possible_hit = self.scene.intersect(ray);

        if let Some(hit) = possible_hit {
            result = self.shade(&hit, ray);

            if hit.shape.material().is_reflective() {
                result = result + self.reflect(&hit, ray, depth);
            }

            if hit.shape.material().is_refractive() {
                result = result + self.refract(&hit, ray, depth);
            }
        }

        result
    }

    fn shade(&self, intersection: &Intersection, original_ray: Ray) -> Color {
        let material: &Material = intersection.shape.material();
        let mut result = material.ambient_color;

        for light in self.scene.lights {
            let mut in_shadow = false;
            let distance_to_light = (intersection.point - light.origin).length();
            let light_direction = (light.origin - intersection.point).normalize();
            let ray = Ray::new(intersection.point + light_direction * EPSILON,
                               light_direction,
                               Some(original_ray.medium_refraction));

            for object in self.scene.objects {
                if let Some(hit) = object.intersect(ray) {
                    if hit.t < distance_to_light {
                        in_shadow = true;
                        break;
                    }
                }
            }

            if in_shadow {
                continue;
            }

            let light_color = light.color();
            let mut dot = light_direction.dot(&intersection.normal);

            // Diffuse
            if dot > 0.0 {
                result = result + (light_color * material.diffuse_color) * dot;
            }

            dot = original_ray.direction.dot(&light_direction.reflect(&intersection.normal));

            // Specular
            if dot > 0.0 {
                let spec = dot.powf(20.0);

                result = result + (light_color * material.specular_color) * spec;
            }
        }

        result
    }

    fn reflect(&self, intersection: &Intersection, original_ray: Ray, current_depth: u32) -> Color {
        let new_direction = original_ray.direction.reflect(&intersection.normal).normalize();

        let new_ray = Ray::new(intersection.point + new_direction * EPSILON,
                               new_direction,
                               Some(original_ray.medium_refraction));

        let reflected_color = self.trace(new_ray, current_depth - 1);

        reflected_color *
        intersection.shape
            .material()
            .reflection_coefficient
            .unwrap_or(0.0)
    }

    fn refract(&self, intersection: &Intersection, original_ray: Ray, current_depth: u32) -> Color {
        assert!(intersection.shape
                    .material()
                    .refraction_coefficient
                    .is_some(),
                "Don't call refract for materials that aren't refractive");
        let mut refraction_coefficient = intersection.shape
            .material()
            .refraction_coefficient
            .unwrap_or(1.0);

        if intersection.inside {
            // Leaving refractive material
            refraction_coefficient = 1.0;
        }

        let n = original_ray.medium_refraction / refraction_coefficient;
        let normal = match intersection.inside {
            true => -intersection.normal,
            false => intersection.normal,
        };

        let cos_i = normal.dot(&original_ray.direction);
        let c2 = 1.0 - n * (1.0 - cos_i * cos_i);

        if c2 > 0.0 {
            let direction = (original_ray.direction * n + normal * (n * cos_i - c2.sqrt()))
                .normalize();

            let new_ray = Ray::new(intersection.point + direction * EPSILON,
                                   direction,
                                   Some(refraction_coefficient));

            let refraction_color = self.trace(new_ray, current_depth - 1);
            let absorbance = intersection.shape.material().ambient_color * 0.15 * -intersection.t;
            let transparency = Color::new_f64(absorbance.r_f64().exp(),
                                              absorbance.g_f64().exp(),
                                              absorbance.b_f64().exp());

            return refraction_color * transparency;

        }

        return Color::black();
    }
}
<|endoftext|>