<commit_before>extern crate llvm_tools;
extern crate target_build_utils;
extern crate walkdir;

use std::env;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use std::process::Command;
use target_build_utils::TargetInfo;
use walkdir::{DirEntry, WalkDir};

fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) {
	assert!(
		src_dir.exists(),
		"rusty_hermit source folder does not exist"
	);
	let target = TargetInfo::new().expect("Could not get target info");
	let profile = env::var("PROFILE").expect("PROFILE was not set");
	let mut cmd = Command::new("cargo");

	if target.target_arch() == "x86_64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("x86_64-unknown-none-hermitkernel");
	} else if target.target_arch() == "aarch64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("aarch64-unknown-hermit");
	} else {
		panic!("Try to build for an unsupported platform");
	}

	if let Some(target_dir) = target_dir_opt {
		cmd.arg("--target-dir").arg(target_dir);
	}
	let target_dir = match target_dir_opt {
		Some(target_dir) => target_dir.to_path_buf(),
		None => src_dir.join("target"),
	};

	if profile == "release" {
		cmd.arg("--release");
	}

	// disable all default features
	cmd.arg("--no-default-features");

	// do we have to enable PCI support?
	#[cfg(feature = "pci")]
	{
		cmd.arg("--features");
		cmd.arg("pci");
	}

	// do we have to enable acpi support?
	#[cfg(feature = "acpi")]
	{
		cmd.arg("--features");
		cmd.arg("acpi");
	}

	// do we have to enable FSGSBASE support?
	#[cfg(feature = "fsgs_base")]
	{
		cmd.arg("--features");
		cmd.arg("fsgs_base");
	}

	// do we support multi-processor systems?
	#[cfg(feature = "smp")]
	{
		cmd.arg("--features");
		cmd.arg("smp");
	}

	// do we have to enable VGA support
	#[cfg(feature = "vga")]
	{
		cmd.arg("--features");
		cmd.arg("vga");
	}

	let mut rustflags = vec!["-Zmutable-noalias=no".to_string()];

	#[cfg(feature = "instrument")]
	{
		rustflags.push("-Zinstrument-mcount".to_string());
		// Add outer `RUSTFLAGS` to command
		if let Ok(var) = env::var("RUSTFLAGS") {
			rustflags.push(var);
		}
	}

	#[cfg(not(feature = "instrument"))]
	{
		// If the `instrument` feature feature is not enabled,
		// filter it from outer `RUSTFLAGS` before adding them to the command.
		if let Ok(var) = env::var("RUSTFLAGS") {
			let flags = var
				.split(',')
				.filter(|&flag| !flag.contains("instrument-mcount"))
				.map(String::from);
			rustflags.extend(flags);
		}
	}

	cmd.env("RUSTFLAGS", rustflags.join(","));

	let status = cmd.status().expect("failed to start kernel build");
	assert!(status.success());

	let lib_location = if target.target_arch() == "x86_64" {
		target_dir
			.join("x86_64-unknown-none-hermitkernel")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else if target.target_arch() == "aarch64" {
		target_dir
			.join("aarch64-unknown-hermit")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else {
		panic!("Try to build for an unsupported platform");
	};
	println!("Lib location: {}", lib_location.display());

	let lib = lib_location.join("libhermit.a");

	rename_symbol("rust_begin_unwind", &lib);
	rename_symbol("rust_oom", &lib);

	#[cfg(feature = "mem")]
	{
		for symbol in ["memcpy", "memmove", "memset", "memcmp", "bcmp"] {
			rename_symbol(symbol, &lib);
		}
	}

	println!("cargo:rustc-link-search=native={}", lib_location.display());
	println!("cargo:rustc-link-lib=static=hermit");

	//HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
	// Doesn't actually rebuild atm - see: https://github.com/rust-lang/cargo/issues/8306
	println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
}

/// Kernel and user space has its own versions of panic handler, oom handler, memcpy, memset, etc,
/// Consequently, we rename the functions in the libos to avoid collisions.
/// In addition, it provides us the offer to create a optimized version of memcpy
/// in user space.
fn rename_symbol(symbol: impl AsRef<OsStr>, lib: impl AsRef<Path>) {
	// Get access to llvm tools shipped in the llvm-tools-preview rustup component
	let llvm_tools = match llvm_tools::LlvmTools::new() {
		Ok(tools) => tools,
		Err(llvm_tools::Error::NotFound) => {
			eprintln!("Error: llvm-tools not found");
			eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?");
			eprintln!("  Install it through: `rustup component add llvm-tools-preview`");
			process::exit(1);
		}
		Err(err) => {
			eprintln!("Failed to retrieve llvm-tools component: {:?}", err);
			process::exit(1);
		}
	};

	// Retrieve path of llvm-objcopy
	let llvm_objcopy = llvm_tools
		.tool(&llvm_tools::exe("llvm-objcopy"))
		.expect("llvm-objcopy not found in llvm-tools");

	// Rename symbols
	let arg = IntoIterator::into_iter([symbol.as_ref(), "=kernel-".as_ref(), symbol.as_ref()])
		.collect::<OsString>();
	let status = Command::new(llvm_objcopy)
		.arg("--redefine-sym")
		.arg(arg)
		.arg(lib.as_ref())
		.status()
		.expect("failed to execute llvm-objcopy");
	assert!(status.success(), "llvm-objcopy was not sucessful");
}

#[cfg(all(not(feature = "rustc-dep-of-std"), not(feature = "with_submodule")))]
fn build() {
	#[cfg(windows)]
	let out_dir = env::temp_dir();
	#[cfg(not(windows))]
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let src_dir = out_dir.join("rusty-hermit");

	if !src_dir.as_path().exists() {
		let status = Command::new("cargo")
			.current_dir(out_dir)
			.arg("download")
			.arg("--output")
			.arg(src_dir.clone().into_os_string())
			.arg("--extract")
			.arg("rusty-hermit")
			.status()
			.expect("failed to start kernel download");
		assert!(
			status.success(),
			"Unable to download rusty-hermit. Is cargo-download installed?"
		);
	}

	build_hermit(src_dir.as_ref(), None);
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn build() {
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let target_dir = out_dir.join("target");
	let src_dir = env::current_dir()
		.unwrap()
		.parent()
		.unwrap()
		.join("libhermit-rs");

	build_hermit(src_dir.as_ref(), Some(target_dir.as_ref()));
	configure_cargo_rerun_if_changed(src_dir.as_ref());
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn configure_cargo_rerun_if_changed(src_dir: &Path) {
	fn is_not_ignored(entry: &DirEntry) -> bool {
		// Ignore .git .vscode and target directories, but not .cargo or .github
		if entry.depth() == 1
			&& entry.path().is_dir()
			&& (entry.path().ends_with("target")
				|| entry.path().ends_with(".git")
				|| entry.path().ends_with(".vscode"))
		{
			return false;
		}
		true
	}

	WalkDir::new(src_dir)
		.into_iter()
		.filter_entry(|e| is_not_ignored(e))
		.filter_map(|v| v.ok())
		.filter_map(|v| v.path().canonicalize().ok())
		.for_each(|x| println!("cargo:rerun-if-changed={}", x.display()));
}

#[cfg(not(feature = "rustc-dep-of-std"))]
fn create_constants() {
	let out_dir = env::var("OUT_DIR").expect("No out dir");
	let dest_path = Path::new(&out_dir).join("constants.rs");
	let mut f = File::create(&dest_path).expect("Could not create file");

	let ip = option_env!("HERMIT_IP");
	let ip = ip.map_or("10.0.5.3", |v| v);

	let gateway = option_env!("HERMIT_GATEWAY");
	let gateway = gateway.map_or("10.0.5.1", |v| v);

	let mask = option_env!("HERMIT_MASK");
	let mask = mask.map_or("255.255.255.0", |v| v);

	writeln!(&mut f, "const HERMIT_IP: &str = \"{}\";", ip).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_IP");

	writeln!(&mut f, "const HERMIT_GATEWAY: &str = \"{}\";", gateway)
		.expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_GATEWAY");

	writeln!(&mut f, "const HERMIT_MASK: &str = \"{}\";", mask).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_MASK");
}

fn main() {
	#[cfg(not(feature = "rustc-dep-of-std"))]
	create_constants();
	#[cfg(not(feature = "rustc-dep-of-std"))]
	build();
}
<commit_msg>build.rs: Enable colored output<commit_after>extern crate llvm_tools;
extern crate target_build_utils;
extern crate walkdir;

use std::env;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use std::process::Command;
use target_build_utils::TargetInfo;
use walkdir::{DirEntry, WalkDir};

fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) {
	assert!(
		src_dir.exists(),
		"rusty_hermit source folder does not exist"
	);
	let target = TargetInfo::new().expect("Could not get target info");
	let profile = env::var("PROFILE").expect("PROFILE was not set");
	let mut cmd = Command::new("cargo");

	cmd.env("CARGO_TERM_COLOR", "always");

	if target.target_arch() == "x86_64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("x86_64-unknown-none-hermitkernel");
	} else if target.target_arch() == "aarch64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("aarch64-unknown-hermit");
	} else {
		panic!("Try to build for an unsupported platform");
	}

	if let Some(target_dir) = target_dir_opt {
		cmd.arg("--target-dir").arg(target_dir);
	}
	let target_dir = match target_dir_opt {
		Some(target_dir) => target_dir.to_path_buf(),
		None => src_dir.join("target"),
	};

	if profile == "release" {
		cmd.arg("--release");
	}

	// disable all default features
	cmd.arg("--no-default-features");

	// do we have to enable PCI support?
	#[cfg(feature = "pci")]
	{
		cmd.arg("--features");
		cmd.arg("pci");
	}

	// do we have to enable acpi support?
	#[cfg(feature = "acpi")]
	{
		cmd.arg("--features");
		cmd.arg("acpi");
	}

	// do we have to enable FSGSBASE support?
	#[cfg(feature = "fsgs_base")]
	{
		cmd.arg("--features");
		cmd.arg("fsgs_base");
	}

	// do we support multi-processor systems?
	#[cfg(feature = "smp")]
	{
		cmd.arg("--features");
		cmd.arg("smp");
	}

	// do we have to enable VGA support
	#[cfg(feature = "vga")]
	{
		cmd.arg("--features");
		cmd.arg("vga");
	}

	let mut rustflags = vec!["-Zmutable-noalias=no".to_string()];

	#[cfg(feature = "instrument")]
	{
		rustflags.push("-Zinstrument-mcount".to_string());
		// Add outer `RUSTFLAGS` to command
		if let Ok(var) = env::var("RUSTFLAGS") {
			rustflags.push(var);
		}
	}

	#[cfg(not(feature = "instrument"))]
	{
		// If the `instrument` feature feature is not enabled,
		// filter it from outer `RUSTFLAGS` before adding them to the command.
		if let Ok(var) = env::var("RUSTFLAGS") {
			let flags = var
				.split(',')
				.filter(|&flag| !flag.contains("instrument-mcount"))
				.map(String::from);
			rustflags.extend(flags);
		}
	}

	cmd.env("RUSTFLAGS", rustflags.join(","));

	let status = cmd.status().expect("failed to start kernel build");
	assert!(status.success());

	let lib_location = if target.target_arch() == "x86_64" {
		target_dir
			.join("x86_64-unknown-none-hermitkernel")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else if target.target_arch() == "aarch64" {
		target_dir
			.join("aarch64-unknown-hermit")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else {
		panic!("Try to build for an unsupported platform");
	};
	println!("Lib location: {}", lib_location.display());

	let lib = lib_location.join("libhermit.a");

	rename_symbol("rust_begin_unwind", &lib);
	rename_symbol("rust_oom", &lib);

	#[cfg(feature = "mem")]
	{
		for symbol in ["memcpy", "memmove", "memset", "memcmp", "bcmp"] {
			rename_symbol(symbol, &lib);
		}
	}

	println!("cargo:rustc-link-search=native={}", lib_location.display());
	println!("cargo:rustc-link-lib=static=hermit");

	//HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
	// Doesn't actually rebuild atm - see: https://github.com/rust-lang/cargo/issues/8306
	println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
}

/// Kernel and user space has its own versions of panic handler, oom handler, memcpy, memset, etc,
/// Consequently, we rename the functions in the libos to avoid collisions.
/// In addition, it provides us the offer to create a optimized version of memcpy
/// in user space.
fn rename_symbol(symbol: impl AsRef<OsStr>, lib: impl AsRef<Path>) {
	// Get access to llvm tools shipped in the llvm-tools-preview rustup component
	let llvm_tools = match llvm_tools::LlvmTools::new() {
		Ok(tools) => tools,
		Err(llvm_tools::Error::NotFound) => {
			eprintln!("Error: llvm-tools not found");
			eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?");
			eprintln!("  Install it through: `rustup component add llvm-tools-preview`");
			process::exit(1);
		}
		Err(err) => {
			eprintln!("Failed to retrieve llvm-tools component: {:?}", err);
			process::exit(1);
		}
	};

	// Retrieve path of llvm-objcopy
	let llvm_objcopy = llvm_tools
		.tool(&llvm_tools::exe("llvm-objcopy"))
		.expect("llvm-objcopy not found in llvm-tools");

	// Rename symbols
	let arg = IntoIterator::into_iter([symbol.as_ref(), "=kernel-".as_ref(), symbol.as_ref()])
		.collect::<OsString>();
	let status = Command::new(llvm_objcopy)
		.arg("--redefine-sym")
		.arg(arg)
		.arg(lib.as_ref())
		.status()
		.expect("failed to execute llvm-objcopy");
	assert!(status.success(), "llvm-objcopy was not sucessful");
}

#[cfg(all(not(feature = "rustc-dep-of-std"), not(feature = "with_submodule")))]
fn build() {
	#[cfg(windows)]
	let out_dir = env::temp_dir();
	#[cfg(not(windows))]
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let src_dir = out_dir.join("rusty-hermit");

	if !src_dir.as_path().exists() {
		let status = Command::new("cargo")
			.current_dir(out_dir)
			.arg("download")
			.arg("--output")
			.arg(src_dir.clone().into_os_string())
			.arg("--extract")
			.arg("rusty-hermit")
			.status()
			.expect("failed to start kernel download");
		assert!(
			status.success(),
			"Unable to download rusty-hermit. Is cargo-download installed?"
		);
	}

	build_hermit(src_dir.as_ref(), None);
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn build() {
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let target_dir = out_dir.join("target");
	let src_dir = env::current_dir()
		.unwrap()
		.parent()
		.unwrap()
		.join("libhermit-rs");

	build_hermit(src_dir.as_ref(), Some(target_dir.as_ref()));
	configure_cargo_rerun_if_changed(src_dir.as_ref());
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn configure_cargo_rerun_if_changed(src_dir: &Path) {
	fn is_not_ignored(entry: &DirEntry) -> bool {
		// Ignore .git .vscode and target directories, but not .cargo or .github
		if entry.depth() == 1
			&& entry.path().is_dir()
			&& (entry.path().ends_with("target")
				|| entry.path().ends_with(".git")
				|| entry.path().ends_with(".vscode"))
		{
			return false;
		}
		true
	}

	WalkDir::new(src_dir)
		.into_iter()
		.filter_entry(|e| is_not_ignored(e))
		.filter_map(|v| v.ok())
		.filter_map(|v| v.path().canonicalize().ok())
		.for_each(|x| println!("cargo:rerun-if-changed={}", x.display()));
}

#[cfg(not(feature = "rustc-dep-of-std"))]
fn create_constants() {
	let out_dir = env::var("OUT_DIR").expect("No out dir");
	let dest_path = Path::new(&out_dir).join("constants.rs");
	let mut f = File::create(&dest_path).expect("Could not create file");

	let ip = option_env!("HERMIT_IP");
	let ip = ip.map_or("10.0.5.3", |v| v);

	let gateway = option_env!("HERMIT_GATEWAY");
	let gateway = gateway.map_or("10.0.5.1", |v| v);

	let mask = option_env!("HERMIT_MASK");
	let mask = mask.map_or("255.255.255.0", |v| v);

	writeln!(&mut f, "const HERMIT_IP: &str = \"{}\";", ip).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_IP");

	writeln!(&mut f, "const HERMIT_GATEWAY: &str = \"{}\";", gateway)
		.expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_GATEWAY");

	writeln!(&mut f, "const HERMIT_MASK: &str = \"{}\";", mask).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_MASK");
}

fn main() {
	#[cfg(not(feature = "rustc-dep-of-std"))]
	create_constants();
	#[cfg(not(feature = "rustc-dep-of-std"))]
	build();
}
<|endoftext|>


<commit_before>/// Simple benchmarks of `find()` performance

macro_rules! make_tests {
    ($n:expr, $m:ident) => {
        mod $m {
            use rayon::prelude::*;
            use test::Bencher;
            use rand::{Rng, SeedableRng, XorShiftRng};

            lazy_static! {
                static ref HAYSTACK: Vec<[u32; $n]> = {
                    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
                    (0..10_000_000).map(|_| {
                        let mut result: [u32; $n] = [0; $n];
                        result[0] = rng.next_u32();
                        result
                    }).collect()
                };
            }

            #[bench]
            fn parallel_find_first(b: &mut Bencher) {
                let needle = HAYSTACK[0][0];
                b.iter(|| assert!(HAYSTACK.par_iter().find(|&&x| x[0] == needle).is_some()));
            }

            #[bench]
            fn serial_find_first(b: &mut Bencher) {
                let needle = HAYSTACK[0][0];
                b.iter(|| assert!(HAYSTACK.iter().find(|&&x| x[0] == needle).is_some()));
            }

            #[bench]
            fn parallel_find_last(b: &mut Bencher) {
                let needle = HAYSTACK[HAYSTACK.len()-1][0];
                b.iter(|| assert!(HAYSTACK.par_iter().find(|&&x| x[0] == needle).is_some()));
            }

            #[bench]
            fn serial_find_last(b: &mut Bencher) {
                let needle = HAYSTACK[HAYSTACK.len()-1][0];
                b.iter(|| assert!(HAYSTACK.iter().find(|&&x| x[0] == needle).is_some()));
            }

            #[bench]
            fn parallel_find_middle(b: &mut Bencher) {
                let needle = HAYSTACK[HAYSTACK.len() / 3 * 2][0];
                b.iter(|| assert!(HAYSTACK.par_iter().find(|&&x| x[0] == needle).is_some()));
            }

            #[bench]
            fn serial_find_middle(b: &mut Bencher) {
                let needle = HAYSTACK[HAYSTACK.len() / 3 * 2][0];
                b.iter(|| assert!(HAYSTACK.iter().find(|&&x| x[0] == needle).is_some()));
            }

            #[bench]
            fn parallel_find_missing(b: &mut Bencher) {
                let needle = HAYSTACK.iter().map(|v| v[0]).max().unwrap() + 1;
                b.iter(|| assert!(HAYSTACK.par_iter().find(|&&x| x[0] == needle).is_none()));
            }

            #[bench]
            fn serial_find_missing(b: &mut Bencher) {
                let needle = HAYSTACK.iter().map(|v| v[0]).max().unwrap() + 1;
                b.iter(|| assert!(HAYSTACK.iter().find(|&&x| x[0] == needle).is_none()));
            }

            #[bench]
            fn parallel_find_common(b: &mut Bencher) {
                b.iter(|| assert!(HAYSTACK.par_iter().find(|&&x| x[0] % 1000 == 999).is_some()));
            }

            #[bench]
            fn serial_find_common(b: &mut Bencher) {
                b.iter(|| assert!(HAYSTACK.iter().find(|&&x| x[0] % 1000 == 999).is_some()));
            }
        }
    }
}

make_tests!(1, size1);
make_tests!(64, size64);
make_tests!(256, size256);
<commit_msg>comment out the larger find benchmarks<commit_after>/// Simple benchmarks of `find()` performance

macro_rules! make_tests {
    ($n:expr, $m:ident) => {
        mod $m {
            use rayon::prelude::*;
            use test::Bencher;
            use rand::{Rng, SeedableRng, XorShiftRng};

            lazy_static! {
                static ref HAYSTACK: Vec<[u32; $n]> = {
                    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
                    (0..10_000_000).map(|_| {
                        let mut result: [u32; $n] = [0; $n];
                        result[0] = rng.next_u32();
                        result
                    }).collect()
                };
            }

            #[bench]
            fn parallel_find_first(b: &mut Bencher) {
                let needle = HAYSTACK[0][0];
                b.iter(|| assert!(HAYSTACK.par_iter().find(|&&x| x[0] == needle).is_some()));
            }

            #[bench]
            fn serial_find_first(b: &mut Bencher) {
                let needle = HAYSTACK[0][0];
                b.iter(|| assert!(HAYSTACK.iter().find(|&&x| x[0] == needle).is_some()));
            }

            #[bench]
            fn parallel_find_last(b: &mut Bencher) {
                let needle = HAYSTACK[HAYSTACK.len()-1][0];
                b.iter(|| assert!(HAYSTACK.par_iter().find(|&&x| x[0] == needle).is_some()));
            }

            #[bench]
            fn serial_find_last(b: &mut Bencher) {
                let needle = HAYSTACK[HAYSTACK.len()-1][0];
                b.iter(|| assert!(HAYSTACK.iter().find(|&&x| x[0] == needle).is_some()));
            }

            #[bench]
            fn parallel_find_middle(b: &mut Bencher) {
                let needle = HAYSTACK[HAYSTACK.len() / 3 * 2][0];
                b.iter(|| assert!(HAYSTACK.par_iter().find(|&&x| x[0] == needle).is_some()));
            }

            #[bench]
            fn serial_find_middle(b: &mut Bencher) {
                let needle = HAYSTACK[HAYSTACK.len() / 3 * 2][0];
                b.iter(|| assert!(HAYSTACK.iter().find(|&&x| x[0] == needle).is_some()));
            }

            #[bench]
            fn parallel_find_missing(b: &mut Bencher) {
                let needle = HAYSTACK.iter().map(|v| v[0]).max().unwrap() + 1;
                b.iter(|| assert!(HAYSTACK.par_iter().find(|&&x| x[0] == needle).is_none()));
            }

            #[bench]
            fn serial_find_missing(b: &mut Bencher) {
                let needle = HAYSTACK.iter().map(|v| v[0]).max().unwrap() + 1;
                b.iter(|| assert!(HAYSTACK.iter().find(|&&x| x[0] == needle).is_none()));
            }

            #[bench]
            fn parallel_find_common(b: &mut Bencher) {
                b.iter(|| assert!(HAYSTACK.par_iter().find(|&&x| x[0] % 1000 == 999).is_some()));
            }

            #[bench]
            fn serial_find_common(b: &mut Bencher) {
                b.iter(|| assert!(HAYSTACK.iter().find(|&&x| x[0] % 1000 == 999).is_some()));
            }
        }
    }
}

make_tests!(1, size1);
// make_tests!(64, size64);
// make_tests!(256, size256);
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::mir::Location;
use rustc::ty::RegionVid;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};

use std::fmt;
use syntax_pos::Span;
use std::ops::Deref;

#[derive(Clone, Default)]
crate struct ConstraintSet {
    constraints: IndexVec<ConstraintIndex, OutlivesConstraint>,
    seen_constraints: FxHashSet<(RegionVid, RegionVid)>,
}

impl ConstraintSet {
    pub fn push(&mut self, constraint: OutlivesConstraint) {
        debug!(
            "add_outlives({:?}: {:?} @ {:?}",
            constraint.sup, constraint.sub, constraint.point
        );
        if constraint.sup == constraint.sub {
            // 'a: 'a is pretty uninteresting
            return;
        }
        if self.seen_constraints.insert(constraint.dedup_key()) {
            self.constraints.push(constraint);
        }
    }

    pub fn link(&mut self, len: usize) -> IndexVec<RegionVid, Option<ConstraintIndex>> {
        let mut map = IndexVec::from_elem_n(None, len);

        for (idx, constraint) in self.constraints.iter_enumerated_mut().rev() {
            let mut head = &mut map[constraint.sub];
            debug_assert!(constraint.next.is_none());
            constraint.next = *head;
            *head = Some(idx);
        }

        map
    }

    pub fn each_affected_by_dirty(
        &self,
        mut opt_dep_idx: Option<ConstraintIndex>,
        mut op: impl FnMut(ConstraintIndex),
    ) {
        while let Some(dep_idx) = opt_dep_idx {
            op(dep_idx);
            opt_dep_idx = self.constraints[dep_idx].next;
        }
    }
}

impl Deref for ConstraintSet {
    type Target = IndexVec<ConstraintIndex, OutlivesConstraint>;

    fn deref(&self) -> &Self::Target { &self.constraints }
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OutlivesConstraint {
    // NB. The ordering here is not significant for correctness, but
    // it is for convenience. Before we dump the constraints in the
    // debugging logs, we sort them, and we'd like the "super region"
    // to be first, etc. (In particular, span should remain last.)
    /// The region SUP must outlive SUB...
    pub sup: RegionVid,

    /// Region that must be outlived.
    pub sub: RegionVid,

    /// At this location.
    pub point: Location,

    /// Later on, we thread the constraints onto a linked list
    /// grouped by their `sub` field. So if you had:
    ///
    /// Index | Constraint | Next Field
    /// ----- | ---------- | ----------
    /// 0     | `'a: 'b`   | Some(2)
    /// 1     | `'b: 'c`   | None
    /// 2     | `'c: 'b`   | None
    pub next: Option<ConstraintIndex>,

    /// Where did this constraint arise?
    pub span: Span,
}

impl OutlivesConstraint {
    pub fn dedup_key(&self) -> (RegionVid, RegionVid) {
        (self.sup, self.sub)
    }
}

impl fmt::Debug for OutlivesConstraint {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(
            formatter,
            "({:?}: {:?} @ {:?}) due to {:?}",
            self.sup, self.sub, self.point, self.span
        )
    }
}

newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" });
<commit_msg>add comments<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::mir::Location;
use rustc::ty::RegionVid;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};

use std::fmt;
use syntax_pos::Span;
use std::ops::Deref;

#[derive(Clone, Default)]
crate struct ConstraintSet {
    constraints: IndexVec<ConstraintIndex, OutlivesConstraint>,
    seen_constraints: FxHashSet<(RegionVid, RegionVid)>,
}

impl ConstraintSet {
    pub fn push(&mut self, constraint: OutlivesConstraint) {
        debug!(
            "add_outlives({:?}: {:?} @ {:?}",
            constraint.sup, constraint.sub, constraint.point
        );
        if constraint.sup == constraint.sub {
            // 'a: 'a is pretty uninteresting
            return;
        }
        if self.seen_constraints.insert(constraint.dedup_key()) {
            self.constraints.push(constraint);
        }
    }

    /// Once all constraints have been added, `link()` is used to thread together the constraints
    /// based on which would be affected when a particular region changes. See the next field of
    /// `OutlivesContraint` for more details.
    /// link returns a map that is needed later by `each_affected_by_dirty`.
    pub fn link(&mut self, len: usize) -> IndexVec<RegionVid, Option<ConstraintIndex>> {
        let mut map = IndexVec::from_elem_n(None, len);

        for (idx, constraint) in self.constraints.iter_enumerated_mut().rev() {
            let mut head = &mut map[constraint.sub];
            debug_assert!(constraint.next.is_none());
            constraint.next = *head;
            *head = Some(idx);
        }

        map
    }

    /// When a region R1 changes, we need to reprocess all constraints R2: R1 to take into account
    /// any new elements that R1 now has. This method will quickly enumerate all such constraints
    /// (that is, constraints where R1 is in the "subregion" position).
    /// To use it, invoke with `map[R1]` where map is the map returned by `link`;
    /// the callback op will be invoked for each affected constraint.
    pub fn each_affected_by_dirty(
        &self,
        mut opt_dep_idx: Option<ConstraintIndex>,
        mut op: impl FnMut(ConstraintIndex),
    ) {
        while let Some(dep_idx) = opt_dep_idx {
            op(dep_idx);
            opt_dep_idx = self.constraints[dep_idx].next;
        }
    }
}

impl Deref for ConstraintSet {
    type Target = IndexVec<ConstraintIndex, OutlivesConstraint>;

    fn deref(&self) -> &Self::Target { &self.constraints }
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OutlivesConstraint {
    // NB. The ordering here is not significant for correctness, but
    // it is for convenience. Before we dump the constraints in the
    // debugging logs, we sort them, and we'd like the "super region"
    // to be first, etc. (In particular, span should remain last.)
    /// The region SUP must outlive SUB...
    pub sup: RegionVid,

    /// Region that must be outlived.
    pub sub: RegionVid,

    /// At this location.
    pub point: Location,

    /// Later on, we thread the constraints onto a linked list
    /// grouped by their `sub` field. So if you had:
    ///
    /// Index | Constraint | Next Field
    /// ----- | ---------- | ----------
    /// 0     | `'a: 'b`   | Some(2)
    /// 1     | `'b: 'c`   | None
    /// 2     | `'c: 'b`   | None
    pub next: Option<ConstraintIndex>,

    /// Where did this constraint arise?
    pub span: Span,
}

impl OutlivesConstraint {
    pub fn dedup_key(&self) -> (RegionVid, RegionVid) {
        (self.sup, self.sub)
    }
}

impl fmt::Debug for OutlivesConstraint {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(
            formatter,
            "({:?}: {:?} @ {:?}) due to {:?}",
            self.sup, self.sub, self.point, self.span
        )
    }
}

newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" });
<|endoftext|>


<commit_before>// Copyright 2019 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(dead_code)]

use peek_poke::{PeekPoke, Poke};
use std::{marker::PhantomData, mem::size_of};

#[test]
fn test_numbers() {
    assert_eq!(u8::max_size(), size_of::<u8>());
    assert_eq!(u16::max_size(), size_of::<u16>());
    assert_eq!(u32::max_size(), size_of::<u32>());
    assert_eq!(u64::max_size(), size_of::<u64>());
    assert_eq!(usize::max_size(), size_of::<usize>());
    assert_eq!(i8::max_size(), size_of::<i8>());
    assert_eq!(i16::max_size(), size_of::<i16>());
    assert_eq!(i32::max_size(), size_of::<i32>());
    assert_eq!(i64::max_size(), size_of::<i64>());
    assert_eq!(isize::max_size(), size_of::<isize>());
    // floating
    assert_eq!(f32::max_size(), size_of::<f32>());
    assert_eq!(f64::max_size(), size_of::<f64>());
}

#[test]
fn test_bool() {
    assert_eq!(bool::max_size(), size_of::<u8>());
}

#[test]
fn test_option() {
    assert_eq!(
        Option::<usize>::max_size(),
        <u8>::max_size() + <usize>::max_size()
    );
}

#[test]
fn test_fixed_size_array() {
    assert_eq!(<[u32; 32]>::max_size(), 32 * size_of::<u32>());
    assert_eq!(<[u64; 8]>::max_size(), 8 * size_of::<u64>());
    assert_eq!(<[u8; 19]>::max_size(), 19 * size_of::<u8>());
}

#[test]
fn test_tuple() {
    assert_eq!(<(isize,)>::max_size(), size_of::<isize>());
    assert_eq!(<(isize, isize, isize)>::max_size(), 3 * size_of::<isize>());
    assert_eq!(<(isize, ())>::max_size(), size_of::<isize>());
}

#[test]
fn test_basic_struct() {
    #[derive(Debug, PeekPoke)]
    struct Bar {
        a: u32,
        b: u32,
        c: u32,
    }

    assert_eq!(<Bar>::max_size(), 3 * <u32>::max_size());
}

#[test]
fn test_enum() {
    #[derive(Clone, Copy, PeekPoke)]
    enum TestEnum {
        NoArg,
        OneArg(usize),
        Args(usize, usize),
        AnotherNoArg,
        StructLike { x: usize, y: f32 },
    }
    assert_eq!(
        TestEnum::max_size(),
        <u8>::max_size() + 2 * <usize>::max_size()
    );
}

#[test]
fn test_enum_cstyle() {
    #[repr(u32)]
    #[derive(Clone, Copy, PeekPoke)]
    enum BorderStyle {
        None = 0,
        Solid = 1,
        Double = 2,
        Dotted = 3,
        Dashed = 4,
        Hidden = 5,
        Groove = 6,
        Ridge = 7,
        Inset = 8,
        Outset = 9,
    }
    assert_eq!(BorderStyle::max_size(), <u8>::max_size());
}

#[test]
fn test_phantom_data() {
    struct Bar;
    #[derive(PeekPoke)]
    struct Foo {
        x: u32,
        y: u32,
        _marker: PhantomData<Bar>,
    }
    assert_eq!(Foo::max_size(), 2 * size_of::<u32>())
}
<commit_msg>Backed out changeset f020ddf90621 (bug 1612988) for causing webrender bustage CLOSED TREE<commit_after>// Copyright 2019 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(dead_code)]

use peek_poke::{PeekPoke, Poke};
use std::{marker::PhantomData, mem::size_of};

#[test]
fn test_numbers() {
    assert_eq!(u8::max_size(), size_of::<u8>());
    assert_eq!(u16::max_size(), size_of::<u16>());
    assert_eq!(u32::max_size(), size_of::<u32>());
    assert_eq!(u64::max_size(), size_of::<u64>());
    assert_eq!(usize::max_size(), size_of::<usize>());
    assert_eq!(i8::max_size(), size_of::<i8>());
    assert_eq!(i16::max_size(), size_of::<i16>());
    assert_eq!(i32::max_size(), size_of::<i32>());
    assert_eq!(i64::max_size(), size_of::<i64>());
    assert_eq!(isize::max_size(), size_of::<isize>());
    // floating
    assert_eq!(f32::max_size(), size_of::<f32>());
    assert_eq!(f64::max_size(), size_of::<f64>());
}

#[test]
fn test_bool() {
    assert_eq!(bool::max_size(), size_of::<u8>());
}

#[test]
fn test_option() {
    assert_eq!(
        Option::<usize>::max_size(),
        <u8>::max_size() + <usize>::max_size()
    );
}

#[test]
fn test_fixed_size_array() {
    assert_eq!(<[u32; 32]>::max_size(), 32 * size_of::<u32>());
    assert_eq!(<[u64; 8]>::max_size(), 8 * size_of::<u64>());
    assert_eq!(<[u8; 19]>::max_size(), 19 * size_of::<u8>());
}

#[test]
fn test_tuple() {
    assert_eq!(<(isize)>::max_size(), size_of::<isize>());
    assert_eq!(<(isize, isize, isize)>::max_size(), 3 * size_of::<isize>());
    assert_eq!(<(isize, ())>::max_size(), size_of::<isize>());
}

#[test]
fn test_basic_struct() {
    #[derive(Debug, PeekPoke)]
    struct Bar {
        a: u32,
        b: u32,
        c: u32,
    }

    assert_eq!(<Bar>::max_size(), 3 * <u32>::max_size());
}

#[test]
fn test_enum() {
    #[derive(Clone, Copy, PeekPoke)]
    enum TestEnum {
        NoArg,
        OneArg(usize),
        Args(usize, usize),
        AnotherNoArg,
        StructLike { x: usize, y: f32 },
    }
    assert_eq!(
        TestEnum::max_size(),
        <u8>::max_size() + 2 * <usize>::max_size()
    );
}

#[test]
fn test_enum_cstyle() {
    #[repr(u32)]
    #[derive(Clone, Copy, PeekPoke)]
    enum BorderStyle {
        None = 0,
        Solid = 1,
        Double = 2,
        Dotted = 3,
        Dashed = 4,
        Hidden = 5,
        Groove = 6,
        Ridge = 7,
        Inset = 8,
        Outset = 9,
    }
    assert_eq!(BorderStyle::max_size(), <u8>::max_size());
}

#[test]
fn test_phantom_data() {
    struct Bar;
    #[derive(PeekPoke)]
    struct Foo {
        x: u32,
        y: u32,
        _marker: PhantomData<Bar>,
    }
    assert_eq!(Foo::max_size(), 2 * size_of::<u32>())
}
<|endoftext|>


<commit_before><commit_msg>Remove unwraps<commit_after><|endoftext|>


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

extern crate byteorder;
extern crate fmt;
#[macro_use]
extern crate log;
extern crate protobuf;

use byteorder::WriteBytesExt;
use proto::oak_api::OakStatus;
use protobuf::{Message, ProtobufEnum};
use std::io;
use std::io::Write;

pub mod proto;
pub mod storage;
#[cfg(test)]
mod tests;

#[cfg(test)]
#[macro_use]
extern crate assert_matches;

pub type GrpcResult<T> = Result<T, proto::status::Status>;

/// Trait to allow repeated writing of responses for server-streaming gRPC methods.
pub trait ResponseWriter<T: protobuf::Message> {
    fn write(&mut self, rsp: T);
}

/// Implementation of ResponseWriter that encapsulates response messages into
/// GrpcResponse wrapper messages and writes serialized versions to a (mutably
/// borrowed) send channel.
pub struct ChannelResponseWriter<'a> {
    pub channel: &'a mut SendChannelHalf,
}

impl<'a, T> ResponseWriter<T> for ChannelResponseWriter<'a>
where
    T: protobuf::Message,
{
    fn write(&mut self, rsp: T) {
        // Put the serialized response into a GrpcResponse message wrapper.
        let mut grpc_rsp = proto::grpc_encap::GrpcResponse::new();
        let mut any = protobuf::well_known_types::Any::new();
        rsp.write_to_writer(&mut any.value).unwrap();
        grpc_rsp.set_rsp_msg(any);
        // Serialize the GrpcResponse into the send channel.
        grpc_rsp.write_to_writer(&mut self.channel).unwrap();
    }
}

pub type Handle = u64;

/// Map an OakStatus to the nearest available std::io::Result.
fn result_from_status<T>(status: Option<OakStatus>, val: T) -> std::io::Result<T> {
    match status {
        Some(OakStatus::OAK_STATUS_UNSPECIFIED) => Err(io::Error::new(
            io::ErrorKind::Other,
            "Unspecified Oak status value",
        )),
        Some(OakStatus::OK) => Ok(val),
        Some(OakStatus::ERR_BAD_HANDLE) => {
            Err(io::Error::new(io::ErrorKind::NotConnected, "Bad handle"))
        }
        Some(OakStatus::ERR_INVALID_ARGS) => Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "Invalid arguments",
        )),
        Some(OakStatus::ERR_CHANNEL_CLOSED) => Err(io::Error::new(
            io::ErrorKind::ConnectionReset,
            "Channel closed",
        )),
        Some(OakStatus::ERR_BUFFER_TOO_SMALL) => Err(io::Error::new(
            io::ErrorKind::UnexpectedEof,
            "Buffer too small",
        )),
        Some(OakStatus::ERR_OUT_OF_RANGE) => {
            Err(io::Error::new(io::ErrorKind::NotConnected, "Out of range"))
        }
        Some(OakStatus::ERR_INTERNAL) => {
            Err(io::Error::new(io::ErrorKind::Other, "Internal error"))
        }
        None => Err(io::Error::new(
            io::ErrorKind::Other,
            "Unknown Oak status value",
        )),
    }
}

// TODO: Implement panic handler.

mod wasm {
    // See https://rustwasm.github.io/book/reference/js-ffi.html
    #[link(wasm_import_module = "oak")]
    extern "C" {
        pub fn wait_on_channels(buf: *mut u8, count: u32) -> i32;
        pub fn channel_read(handle: u64, buf: *mut u8, size: usize, actual_size: *mut u32) -> i32;
        pub fn channel_write(handle: u64, buf: *const u8, size: usize) -> i32;
        pub fn channel_find(buf: *const u8, len: usize) -> u64;
    }
}

pub fn channel_find(port_name: &str) -> Handle {
    unsafe { wasm::channel_find(port_name.as_ptr(), port_name.len()) }
}

pub const SPACE_BYTES_PER_HANDLE: usize = 9;

// Build a chunk of memory that is suitable for passing to wasm::wait_on_channels,
// holding the given collection of channel handles.
fn new_handle_space(handles: &[Handle]) -> Vec<u8> {
    let mut space = Vec::with_capacity(SPACE_BYTES_PER_HANDLE * handles.len());
    for handle in handles {
        space.write_u64::<byteorder::LittleEndian>(*handle).unwrap();
        space.push(0x00);
    }
    space
}

// Prepare a handle space for polling by clearing all of the message-pending
// indicator bytes.
fn prep_handle_space(space: &mut [u8]) {
    let count = space.len() / 8;
    for i in 0..count {
        space[i * SPACE_BYTES_PER_HANDLE + (SPACE_BYTES_PER_HANDLE - 1)] = 0;
    }
}

pub struct SendChannelHalf {
    handle: Handle,
}

impl SendChannelHalf {
    pub fn new(handle: Handle) -> SendChannelHalf {
        SendChannelHalf { handle }
    }

    pub fn write_message(&mut self, buf: &[u8]) -> std::io::Result<()> {
        result_from_status(
            OakStatus::from_i32(unsafe {
                wasm::channel_write(self.handle, buf.as_ptr(), buf.len())
            }),
            (),
        )
    }
}

// Implement the Write trait on a send channel for convenience, particularly for
// the logging channel.
impl Write for SendChannelHalf {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        match self.write_message(buf) {
            Ok(_) => Ok(buf.len()),
            Err(e) => Err(e),
        }
    }
    fn flush(&mut self) -> std::io::Result<()> {
        Ok(())
    }
}

pub fn logging_channel() -> impl Write {
    let logging_channel = SendChannelHalf::new(channel_find("log"));
    // Only flush logging channel on newlines.
    std::io::LineWriter::new(logging_channel)
}

pub struct ReceiveChannelHalf {
    handle: Handle,
}

impl ReceiveChannelHalf {
    pub fn new(handle: Handle) -> ReceiveChannelHalf {
        ReceiveChannelHalf { handle }
    }

    pub fn read_message(&mut self, buf: &mut Vec<u8>) -> std::io::Result<usize> {
        // Try reading from the channel twice: first with provided vector,
        // then with a vector that's been resized to meet size requirements.
        for resized in &[false, true] {
            let mut actual_size: u32 = 0;
            let status = OakStatus::from_i32(unsafe {
                wasm::channel_read(
                    self.handle,
                    buf.as_mut_ptr(),
                    buf.capacity(),
                    &mut actual_size,
                )
            });
            match status {
                Some(OakStatus::OK) => {
                    unsafe {
                        buf.set_len(actual_size as usize);
                    };
                    return Ok(actual_size as usize);
                }
                Some(OakStatus::ERR_BUFFER_TOO_SMALL) => {
                    if *resized {
                        return result_from_status(status, 0);
                    }
                    // Can escape the match if buffer is too small and !resized.
                }
                _ => return result_from_status(status, 0),
            }

            // Extend the vector to be large enough for the message
            debug!("Got {}, need {}", buf.capacity(), actual_size);
            if (actual_size as usize) < buf.len() {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!(
                        "Internal error: provided {} bytes for receive, asked for {}",
                        buf.len(),
                        actual_size
                    ),
                ));
            }
            let extra = (actual_size as usize) - buf.len();
            buf.reserve(extra);
        }
        Err(io::Error::new(io::ErrorKind::Other, "Unreachable reached!"))
    }
}

/// Convenience wrapper for a send/receive pair of channels.
pub struct ChannelPair {
    pub receive: ReceiveChannelHalf,
    pub send: SendChannelHalf,
}

impl ChannelPair {
    pub fn new(in_handle: Handle, out_handle: Handle) -> ChannelPair {
        ChannelPair {
            receive: ReceiveChannelHalf::new(in_handle),
            send: SendChannelHalf::new(out_handle),
        }
    }
}

/// Trait encapsulating the operations required for an Oak Node.
pub trait OakNode {
    fn new() -> Self
    where
        Self: Sized;
    fn invoke(&mut self, method: &str, req: &[u8], out: &mut SendChannelHalf);
}

/// Perform a gRPC event loop on the given channels, invoking the given node.
pub fn grpc_event_loop<T: OakNode>(
    mut node: T,
    grpc_in_handle: Handle,
    grpc_out_handle: Handle,
) -> i32 {
    info!(
        "start event loop for node with handles in:{} out:{}",
        grpc_in_handle, grpc_out_handle
    );
    if grpc_in_handle == 0 || grpc_out_handle == 0 {
        return OakStatus::ERR_CHANNEL_CLOSED.value();
    }
    set_panic_hook();

    let read_handles = vec![grpc_in_handle];
    let mut space = new_handle_space(&read_handles);

    let mut grpc_in_channel = ReceiveChannelHalf::new(grpc_in_handle);
    let mut grpc_out_channel = SendChannelHalf::new(grpc_out_handle);
    loop {
        // Block until there is a message to read on an input channel.
        prep_handle_space(&mut space);
        unsafe {
            let status = wasm::wait_on_channels(space.as_mut_ptr(), read_handles.len() as u32);
            match OakStatus::from_i32(status) {
                Some(OakStatus::OK) => (),
                Some(err) => return err as i32,
                None => return OakStatus::OAK_STATUS_UNSPECIFIED.value(),
            }
        }

        let mut buf = Vec::<u8>::with_capacity(1024);
        grpc_in_channel.read_message(&mut buf).unwrap();
        if buf.is_empty() {
            info!("no pending message; poll again");
            continue;
        }
        let req: proto::grpc_encap::GrpcRequest = protobuf::parse_from_bytes(&buf).unwrap();
        if !req.last {
            panic!("Support for streaming requests not yet implemented");
        }
        node.invoke(
            &req.method_name,
            req.get_req_msg().value.as_slice(),
            &mut grpc_out_channel,
        );
    }
}

/// Install a panic hook so that panics are logged to the logging channel, if one is set.
/// See https://doc.rust-lang.org/std/panic/struct.PanicInfo.html.
fn set_panic_hook() {
    std::panic::set_hook(Box::new(|panic_info| {
        let msg = panic_info
            .payload()
            .downcast_ref::<&str>()
            .unwrap_or(&"<UNKWOWN MESSAGE>");
        let (file, line) = match panic_info.location() {
            Some(location) => (location.file(), location.line()),
            None => ("<UNKNOWN FILE>", 0),
        };
        error!(
            "panic occurred in file '{}' at line {}: {}",
            file, line, msg
        );
    }));
}
<commit_msg>Remove done TODO comment<commit_after>//
// Copyright 2018 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

extern crate byteorder;
extern crate fmt;
#[macro_use]
extern crate log;
extern crate protobuf;

use byteorder::WriteBytesExt;
use proto::oak_api::OakStatus;
use protobuf::{Message, ProtobufEnum};
use std::io;
use std::io::Write;

pub mod proto;
pub mod storage;
#[cfg(test)]
mod tests;

#[cfg(test)]
#[macro_use]
extern crate assert_matches;

pub type GrpcResult<T> = Result<T, proto::status::Status>;

/// Trait to allow repeated writing of responses for server-streaming gRPC methods.
pub trait ResponseWriter<T: protobuf::Message> {
    fn write(&mut self, rsp: T);
}

/// Implementation of ResponseWriter that encapsulates response messages into
/// GrpcResponse wrapper messages and writes serialized versions to a (mutably
/// borrowed) send channel.
pub struct ChannelResponseWriter<'a> {
    pub channel: &'a mut SendChannelHalf,
}

impl<'a, T> ResponseWriter<T> for ChannelResponseWriter<'a>
where
    T: protobuf::Message,
{
    fn write(&mut self, rsp: T) {
        // Put the serialized response into a GrpcResponse message wrapper.
        let mut grpc_rsp = proto::grpc_encap::GrpcResponse::new();
        let mut any = protobuf::well_known_types::Any::new();
        rsp.write_to_writer(&mut any.value).unwrap();
        grpc_rsp.set_rsp_msg(any);
        // Serialize the GrpcResponse into the send channel.
        grpc_rsp.write_to_writer(&mut self.channel).unwrap();
    }
}

pub type Handle = u64;

/// Map an OakStatus to the nearest available std::io::Result.
fn result_from_status<T>(status: Option<OakStatus>, val: T) -> std::io::Result<T> {
    match status {
        Some(OakStatus::OAK_STATUS_UNSPECIFIED) => Err(io::Error::new(
            io::ErrorKind::Other,
            "Unspecified Oak status value",
        )),
        Some(OakStatus::OK) => Ok(val),
        Some(OakStatus::ERR_BAD_HANDLE) => {
            Err(io::Error::new(io::ErrorKind::NotConnected, "Bad handle"))
        }
        Some(OakStatus::ERR_INVALID_ARGS) => Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "Invalid arguments",
        )),
        Some(OakStatus::ERR_CHANNEL_CLOSED) => Err(io::Error::new(
            io::ErrorKind::ConnectionReset,
            "Channel closed",
        )),
        Some(OakStatus::ERR_BUFFER_TOO_SMALL) => Err(io::Error::new(
            io::ErrorKind::UnexpectedEof,
            "Buffer too small",
        )),
        Some(OakStatus::ERR_OUT_OF_RANGE) => {
            Err(io::Error::new(io::ErrorKind::NotConnected, "Out of range"))
        }
        Some(OakStatus::ERR_INTERNAL) => {
            Err(io::Error::new(io::ErrorKind::Other, "Internal error"))
        }
        None => Err(io::Error::new(
            io::ErrorKind::Other,
            "Unknown Oak status value",
        )),
    }
}

mod wasm {
    // See https://rustwasm.github.io/book/reference/js-ffi.html
    #[link(wasm_import_module = "oak")]
    extern "C" {
        pub fn wait_on_channels(buf: *mut u8, count: u32) -> i32;
        pub fn channel_read(handle: u64, buf: *mut u8, size: usize, actual_size: *mut u32) -> i32;
        pub fn channel_write(handle: u64, buf: *const u8, size: usize) -> i32;
        pub fn channel_find(buf: *const u8, len: usize) -> u64;
    }
}

pub fn channel_find(port_name: &str) -> Handle {
    unsafe { wasm::channel_find(port_name.as_ptr(), port_name.len()) }
}

pub const SPACE_BYTES_PER_HANDLE: usize = 9;

// Build a chunk of memory that is suitable for passing to wasm::wait_on_channels,
// holding the given collection of channel handles.
fn new_handle_space(handles: &[Handle]) -> Vec<u8> {
    let mut space = Vec::with_capacity(SPACE_BYTES_PER_HANDLE * handles.len());
    for handle in handles {
        space.write_u64::<byteorder::LittleEndian>(*handle).unwrap();
        space.push(0x00);
    }
    space
}

// Prepare a handle space for polling by clearing all of the message-pending
// indicator bytes.
fn prep_handle_space(space: &mut [u8]) {
    let count = space.len() / 8;
    for i in 0..count {
        space[i * SPACE_BYTES_PER_HANDLE + (SPACE_BYTES_PER_HANDLE - 1)] = 0;
    }
}

pub struct SendChannelHalf {
    handle: Handle,
}

impl SendChannelHalf {
    pub fn new(handle: Handle) -> SendChannelHalf {
        SendChannelHalf { handle }
    }

    pub fn write_message(&mut self, buf: &[u8]) -> std::io::Result<()> {
        result_from_status(
            OakStatus::from_i32(unsafe {
                wasm::channel_write(self.handle, buf.as_ptr(), buf.len())
            }),
            (),
        )
    }
}

// Implement the Write trait on a send channel for convenience, particularly for
// the logging channel.
impl Write for SendChannelHalf {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        match self.write_message(buf) {
            Ok(_) => Ok(buf.len()),
            Err(e) => Err(e),
        }
    }
    fn flush(&mut self) -> std::io::Result<()> {
        Ok(())
    }
}

pub fn logging_channel() -> impl Write {
    let logging_channel = SendChannelHalf::new(channel_find("log"));
    // Only flush logging channel on newlines.
    std::io::LineWriter::new(logging_channel)
}

pub struct ReceiveChannelHalf {
    handle: Handle,
}

impl ReceiveChannelHalf {
    pub fn new(handle: Handle) -> ReceiveChannelHalf {
        ReceiveChannelHalf { handle }
    }

    pub fn read_message(&mut self, buf: &mut Vec<u8>) -> std::io::Result<usize> {
        // Try reading from the channel twice: first with provided vector,
        // then with a vector that's been resized to meet size requirements.
        for resized in &[false, true] {
            let mut actual_size: u32 = 0;
            let status = OakStatus::from_i32(unsafe {
                wasm::channel_read(
                    self.handle,
                    buf.as_mut_ptr(),
                    buf.capacity(),
                    &mut actual_size,
                )
            });
            match status {
                Some(OakStatus::OK) => {
                    unsafe {
                        buf.set_len(actual_size as usize);
                    };
                    return Ok(actual_size as usize);
                }
                Some(OakStatus::ERR_BUFFER_TOO_SMALL) => {
                    if *resized {
                        return result_from_status(status, 0);
                    }
                    // Can escape the match if buffer is too small and !resized.
                }
                _ => return result_from_status(status, 0),
            }

            // Extend the vector to be large enough for the message
            debug!("Got {}, need {}", buf.capacity(), actual_size);
            if (actual_size as usize) < buf.len() {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!(
                        "Internal error: provided {} bytes for receive, asked for {}",
                        buf.len(),
                        actual_size
                    ),
                ));
            }
            let extra = (actual_size as usize) - buf.len();
            buf.reserve(extra);
        }
        Err(io::Error::new(io::ErrorKind::Other, "Unreachable reached!"))
    }
}

/// Convenience wrapper for a send/receive pair of channels.
pub struct ChannelPair {
    pub receive: ReceiveChannelHalf,
    pub send: SendChannelHalf,
}

impl ChannelPair {
    pub fn new(in_handle: Handle, out_handle: Handle) -> ChannelPair {
        ChannelPair {
            receive: ReceiveChannelHalf::new(in_handle),
            send: SendChannelHalf::new(out_handle),
        }
    }
}

/// Trait encapsulating the operations required for an Oak Node.
pub trait OakNode {
    fn new() -> Self
    where
        Self: Sized;
    fn invoke(&mut self, method: &str, req: &[u8], out: &mut SendChannelHalf);
}

/// Perform a gRPC event loop on the given channels, invoking the given node.
pub fn grpc_event_loop<T: OakNode>(
    mut node: T,
    grpc_in_handle: Handle,
    grpc_out_handle: Handle,
) -> i32 {
    info!(
        "start event loop for node with handles in:{} out:{}",
        grpc_in_handle, grpc_out_handle
    );
    if grpc_in_handle == 0 || grpc_out_handle == 0 {
        return OakStatus::ERR_CHANNEL_CLOSED.value();
    }
    set_panic_hook();

    let read_handles = vec![grpc_in_handle];
    let mut space = new_handle_space(&read_handles);

    let mut grpc_in_channel = ReceiveChannelHalf::new(grpc_in_handle);
    let mut grpc_out_channel = SendChannelHalf::new(grpc_out_handle);
    loop {
        // Block until there is a message to read on an input channel.
        prep_handle_space(&mut space);
        unsafe {
            let status = wasm::wait_on_channels(space.as_mut_ptr(), read_handles.len() as u32);
            match OakStatus::from_i32(status) {
                Some(OakStatus::OK) => (),
                Some(err) => return err as i32,
                None => return OakStatus::OAK_STATUS_UNSPECIFIED.value(),
            }
        }

        let mut buf = Vec::<u8>::with_capacity(1024);
        grpc_in_channel.read_message(&mut buf).unwrap();
        if buf.is_empty() {
            info!("no pending message; poll again");
            continue;
        }
        let req: proto::grpc_encap::GrpcRequest = protobuf::parse_from_bytes(&buf).unwrap();
        if !req.last {
            panic!("Support for streaming requests not yet implemented");
        }
        node.invoke(
            &req.method_name,
            req.get_req_msg().value.as_slice(),
            &mut grpc_out_channel,
        );
    }
}

/// Install a panic hook so that panics are logged to the logging channel, if one is set.
/// See https://doc.rust-lang.org/std/panic/struct.PanicInfo.html.
fn set_panic_hook() {
    std::panic::set_hook(Box::new(|panic_info| {
        let msg = panic_info
            .payload()
            .downcast_ref::<&str>()
            .unwrap_or(&"<UNKWOWN MESSAGE>");
        let (file, line) = match panic_info.location() {
            Some(location) => (location.file(), location.line()),
            None => ("<UNKNOWN FILE>", 0),
        };
        error!(
            "panic occurred in file '{}' at line {}: {}",
            file, line, msg
        );
    }));
}
<|endoftext|>


<commit_before>//! This module provides casting iterators for certain types of accessors.

/// Casting iterator and accompanying types for `Colors`.
pub mod colors;
/// Casting iterator and accompanying types for `Indices`.
pub mod indices;
/// Casting iterator and accompanying types for `Joints`.
pub mod joints;
/// Casting iterator and accompanying types for `TexCoords`.
pub mod tex_coords;
/// Casting iterator and accompanying types for `Weights`.
pub mod weights;
/// Casting iterator and accompanying types for `MorphWeights`.
pub mod morph_weights;
/// Casting iterator and accompanying types for `Rotations`.
pub mod rotations;

#[inline]
fn norm_i8_as_f32(x: i8) -> f32 {
    (x as f32 * (i8::max_value() as f32).recip()).max(-1.0)
}

#[inline]
fn norm_u8_as_u16(x: u8) -> u16 {
    x as u16 * 0x100
}

#[inline]
fn norm_u8_as_f32(x: u8) -> f32 {
    x as f32 * (u8::max_value() as f32).recip()
}

#[inline]
fn norm_i16_as_f32(x: i16) -> f32 {
    (x as f32 * (i16::max_value() as f32).recip()).max(-1.0)
}

#[inline]
fn norm_u16_as_u8(x: u16) -> u8 {
    (x / 0x100) as u8
}

#[inline]
fn norm_u16_as_f32(x: u16) -> f32 {
    x as f32 * (u16::max_value() as f32).recip()
}

#[inline]
fn norm_f32_as_u8(x: f32) -> u8 {
    let hi = u8::max_value() as f32;
    let lo = 0.0;
    (x * hi).max(lo).min(hi) as u8
}

#[inline]
fn norm_f32_as_u16(x: f32) -> u16 {
    let hi = u16::max_value() as f32;
    let lo = 0.0;
    (x * hi).max(lo).min(hi) as u16
}
<commit_msg>Add Normalizable trait back.<commit_after>//! This module provides casting iterators for certain types of accessors.

/// Casting iterator and accompanying types for `Colors`.
pub mod colors;
/// Casting iterator and accompanying types for `Indices`.
pub mod indices;
/// Casting iterator and accompanying types for `Joints`.
pub mod joints;
/// Casting iterator and accompanying types for `TexCoords`.
pub mod tex_coords;
/// Casting iterator and accompanying types for `Weights`.
pub mod weights;
/// Casting iterator and accompanying types for `MorphWeights`.
pub mod morph_weights;
/// Casting iterator and accompanying types for `Rotations`.
pub mod rotations;

trait Normalizable<T> {
    fn normalize(self) -> T;
}

impl Normalizable<i8> for i8 {
    fn normalize(self) -> i8 { self }
}

impl Normalizable<u8> for i8 {
    fn normalize(self) -> u8 { self.max(0) as u8 * 2 }
}

impl Normalizable<i16> for i8 {
    fn normalize(self) -> i16 { self as i16 * 0x100 }
}

impl Normalizable<u16> for i8 {
    fn normalize(self) -> u16 { self.max(0) as u16 * 0x200 }
}

impl Normalizable<f32> for i8 {
    fn normalize(self) -> f32 { (self as f32 * 127.0_f32.recip()).max(-1.0) }
}

impl Normalizable<i8> for u8 {
    fn normalize(self) -> i8 { (self / 2) as i8 }
}

impl Normalizable<u8> for u8 {
    fn normalize(self) -> u8 { self }
}

impl Normalizable<i16> for u8 {
    fn normalize(self) -> i16 { self as i16 * 0x80 }
}

impl Normalizable<u16> for u8 {
    fn normalize(self) -> u16 { self.max(0) as u16 * 2 }
}

impl Normalizable<f32> for u8 {
    fn normalize(self) -> f32 { (self as f32 * 32767.0_f32.recip()).max(-1.0) }
}

impl Normalizable<i8> for i16 {
    fn normalize(self) -> i8 { (self / 0x100) as i8 }
}

impl Normalizable<u8> for i16 {
    fn normalize(self) -> u8 { (self.max(0) / 0x80) as u8 }
}

impl Normalizable<i16> for i16 {
    fn normalize(self) -> i16 { self }
}

impl Normalizable<u16> for i16 {
    fn normalize(self) -> u16 { self.max(0) as u16 * 2 }
}

impl Normalizable<f32> for i16 {
    fn normalize(self) -> f32 { (self as f32 * 32767.0_f32.recip()).max(-1.0) }
}

impl Normalizable<i8> for u16 {
    fn normalize(self) -> i8 { (self / 0x200) as i8 }
}

impl Normalizable<u8> for u16 {
    fn normalize(self) -> u8 { (self / 0x100) as u8 }
}

impl Normalizable<i16> for u16 {
    fn normalize(self) -> i16 { (self / 2) as i16 }
}

impl Normalizable<u16> for u16 {
    fn normalize(self) -> u16 { self }
}

impl Normalizable<f32> for u16 {
    fn normalize(self) -> f32 { self as f32 * 65535.0_f32.recip() }
}

impl Normalizable<i8> for f32 {
    fn normalize(self) -> i8 { (self * 127.0) as i8 }
}

impl Normalizable<u8> for f32 {
    fn normalize(self) -> u8 { (self.max(0.0) * 255.0) as u8 }
}

impl Normalizable<i16> for f32 {
    fn normalize(self) -> i16 { (self * 32767.0) as i16 }
}

impl Normalizable<u16> for f32 {
    fn normalize(self) -> u16 { (self.max(0.0) * 65535.0) as u16 }
}

impl Normalizable<f32> for f32 {
    fn normalize(self) -> f32 { self }
}

impl<U, T> Normalizable<[T; 2]> for [U; 2] where U: Normalizable<T> + Copy {
    fn normalize(self) -> [T; 2] {
        [self[0].normalize(), self[1].normalize()]
    }
}

impl<U, T> Normalizable<[T; 3]> for [U; 3] where U: Normalizable<T> + Copy {
    fn normalize(self) -> [T; 3] {
        [self[0].normalize(), self[1].normalize(), self[2].normalize()]
    }
}

impl<U, T> Normalizable<[T; 4]> for [U; 4] where U: Normalizable<T> + Copy {
    fn normalize(self) -> [T; 4] {
        [self[0].normalize(), self[1].normalize(), self[2].normalize(), self[3].normalize()]
    }
}

#[inline]
fn norm_i8_as_f32(x: i8) -> f32 {
    (x as f32 * (i8::max_value() as f32).recip()).max(-1.0)
}

#[inline]
fn norm_u8_as_u16(x: u8) -> u16 {
    x as u16 * 0x100
}

#[inline]
fn norm_u8_as_f32(x: u8) -> f32 {
    x as f32 * (u8::max_value() as f32).recip()
}

#[inline]
fn norm_i16_as_f32(x: i16) -> f32 {
    (x as f32 * (i16::max_value() as f32).recip()).max(-1.0)
}

#[inline]
fn norm_u16_as_u8(x: u16) -> u8 {
    (x / 0x100) as u8
}

#[inline]
fn norm_u16_as_f32(x: u16) -> f32 {
    x as f32 * (u16::max_value() as f32).recip()
}

#[inline]
fn norm_f32_as_u8(x: f32) -> u8 {
    let hi = u8::max_value() as f32;
    let lo = 0.0;
    (x * hi).max(lo).min(hi) as u8
}

#[inline]
fn norm_f32_as_u16(x: f32) -> u16 {
    let hi = u16::max_value() as f32;
    let lo = 0.0;
    (x * hi).max(lo).min(hi) as u16
}
<|endoftext|>


<commit_before>use utils::*;

pub mod exports {
    use stdweb::js_export;
    use stdweb::web::TypedArray;
    use stdweb::serde::Serde;

    #[js_export]
    fn i8_to_i8( value: i8 ) -> i8 { value + 1 }

    #[js_export]
    fn i16_to_i16( value: i16 ) -> i16 { value + 1 }

    #[js_export]
    fn i32_to_i32( value: i32 ) -> i32 { value + 1 }

    #[js_export]
    fn u8_to_u8( value: u8 ) -> u8 { value + 1 }

    #[js_export]
    fn u16_to_u16( value: u16 ) -> u16 { value + 1 }

    #[js_export]
    fn u32_to_u32( value: u32 ) -> u32 { value + 1 }

    #[js_export]
    fn f64_to_f64( value: f64 ) -> f64 { value * 2.0 }

    #[js_export]
    fn add_two_u32( a: u32, b: u32 ) -> u32 { a + b }

    #[js_export]
    fn rstr_to_string( string: &str ) -> String {
        format!( "{}...", string )
    }

    #[js_export]
    fn string_to_string( string: String ) -> String {
        format!( "{}...", string )
    }

    #[js_export]
    fn rstr() -> &'static str {
        "A string"
    }

    #[js_export]
    fn bool_to_bool( value: bool ) -> bool {
        !value
    }

    #[js_export]
    fn vec_to_vec( input: Vec< u8 > ) -> Vec< u8 > {
        input.into_iter().map( |value| value + 1 ).collect()
    }

    #[js_export]
    fn slice_to_vec( input: &[u8] ) -> Vec< u8 > {
        input.iter().map( |&value| value + 1 ).collect()
    }

    #[js_export]
    fn slice() -> &'static [u8] {
        &[ 1, 2, 3 ]
    }

    #[js_export]
    fn typed_array_to_typed_array_identity( array: TypedArray< u8 > ) -> TypedArray< u8 > {
        array
    }

    #[js_export]
    fn typed_array_to_typed_array( array: TypedArray< u8 > ) -> TypedArray< u8 > {
        let vec: Vec< _ > = array.to_vec().into_iter().map( |value| value + 1 ).collect();
        vec.as_slice().into()
    }

    #[derive(Serialize, Deserialize)]
    pub struct Structure {
        field: i32
    }

    js_serializable!( Structure );
    js_deserializable!( Structure );

    #[js_export]
    fn structure_to_structure( structure: Structure ) -> Structure {
        Structure { field: structure.field + 1 }
    }

    #[derive(Serialize, Deserialize)]
    pub struct PlainStructure {
        field: i32
    }

    #[js_export]
    fn serde_structure_to_serde_structure( structure: Serde< PlainStructure > ) -> Serde< PlainStructure > {
        Serde( PlainStructure { field: structure.0.field + 1 } )
    }
}

pub fn run() {
    test( "i8_to_i8", || { js! { assert.strictEqual( Module.exports.i8_to_i8( 33 ), 34 ); }});
    test( "i16_to_i16", || { js! { assert.strictEqual( Module.exports.i16_to_i16( 33 ), 34 ); }});
    test( "i32_to_i32", || { js! { assert.strictEqual( Module.exports.i32_to_i32( 33 ), 34 ); }});
    test( "u8_to_u8", || { js! { assert.strictEqual( Module.exports.u8_to_u8( 33 ), 34 ); }});
    test( "u16_to_ui6", || { js! { assert.strictEqual( Module.exports.u16_to_u16( 33 ), 34 ); }});
    test( "u32_to_u32", || { js! { assert.strictEqual( Module.exports.u32_to_u32( 33 ), 34 ); }});
    test( "f64_to_f64", || { js! { assert.strictEqual( Module.exports.f64_to_f64( 3.33 ), 6.66 ); }});

    test( "add_two_u32", || { js! { assert.strictEqual( Module.exports.add_two_u32( 123, 1000 ), 1123 ); }});

    test( "rstr_to_string", || { js! {
        assert.strictEqual( Module.exports.rstr_to_string( "ABC" ), "ABC..." );
    }});

    test( "string_to_string", || { js! {
        assert.strictEqual( Module.exports.string_to_string( "ABC" ), "ABC..." );
    }});

    test( "rstr", || { js! {
        assert.strictEqual( Module.exports.rstr(), "A string" );
    }});

    test( "bool_to_bool", || { js! {
        assert.strictEqual( Module.exports.bool_to_bool( true ), false );
        assert.strictEqual( Module.exports.bool_to_bool( false ), true );
    }});

    test( "vec_to_vec", || { js! {
        assert.deepEqual( Module.exports.vec_to_vec( [ 1, 2, 3 ] ), [ 2, 3, 4 ] );
    }});

    test( "slice_to_vec", || { js! {
        assert.deepEqual( Module.exports.slice_to_vec( [ 1, 2, 3 ] ), [ 2, 3, 4 ] );
    }});

    test( "slice", || { js! {
        assert.deepEqual( Module.exports.slice(), [ 1, 2, 3 ] );
    }});

    test( "typed_array_to_typed_array_identity", || { js! {
        let array_in = Uint8Array.from( [ 1, 2, 3 ] );
        let array_out = Module.exports.typed_array_to_typed_array_identity( array_in );
        assert.strictEqual( array_in, array_out );
    }});

    test( "typed_array_to_typed_array", || { js! {
        let array_in = Uint8Array.from( [ 1, 2, 3 ] );
        let array_out = Module.exports.typed_array_to_typed_array( array_in );
        assert.deepEqual( Array.from( array_in ), [ 1, 2, 3 ] );
        assert.deepEqual( Array.from( array_out ), [ 2, 3, 4 ] );
    }});

    test( "structure_to_structure", || { js! {
        let output = Module.exports.structure_to_structure( { field: 1 } );
        assert.deepEqual( output, { field: 2 } );
    }});

    test( "serde_structure_to_serde_structure", || { js! {
        let output = Module.exports.serde_structure_to_serde_structure( { field: 1 } );
        assert.deepEqual( output, { field: 2 } );
    }});
}
<commit_msg>Add yet another `#[js_export]` test<commit_after>use utils::*;

pub mod exports {
    use stdweb::js_export;
    use stdweb::web::TypedArray;
    use stdweb::serde::Serde;

    #[js_export]
    fn i8_to_i8( value: i8 ) -> i8 { value + 1 }

    #[js_export]
    fn i16_to_i16( value: i16 ) -> i16 { value + 1 }

    #[js_export]
    fn i32_to_i32( value: i32 ) -> i32 { value + 1 }

    #[js_export]
    fn u8_to_u8( value: u8 ) -> u8 { value + 1 }

    #[js_export]
    fn u16_to_u16( value: u16 ) -> u16 { value + 1 }

    #[js_export]
    fn u32_to_u32( value: u32 ) -> u32 { value + 1 }

    #[js_export]
    fn f64_to_f64( value: f64 ) -> f64 { value * 2.0 }

    #[js_export]
    fn add_two_u32( a: u32, b: u32 ) -> u32 { a + b }

    #[js_export]
    fn rstr_to_string( string: &str ) -> String {
        format!( "{}...", string )
    }

    #[js_export]
    fn string_to_string( string: String ) -> String {
        format!( "{}...", string )
    }

    #[js_export]
    fn rstr() -> &'static str {
        "A string"
    }

    #[js_export]
    fn join_two_strings( first: &str, second: &str ) -> String {
        let mut result = String::new();
        result.push_str( first );
        result.push_str( second );

        result
    }

    #[js_export]
    fn bool_to_bool( value: bool ) -> bool {
        !value
    }

    #[js_export]
    fn vec_to_vec( input: Vec< u8 > ) -> Vec< u8 > {
        input.into_iter().map( |value| value + 1 ).collect()
    }

    #[js_export]
    fn slice_to_vec( input: &[u8] ) -> Vec< u8 > {
        input.iter().map( |&value| value + 1 ).collect()
    }

    #[js_export]
    fn slice() -> &'static [u8] {
        &[ 1, 2, 3 ]
    }

    #[js_export]
    fn typed_array_to_typed_array_identity( array: TypedArray< u8 > ) -> TypedArray< u8 > {
        array
    }

    #[js_export]
    fn typed_array_to_typed_array( array: TypedArray< u8 > ) -> TypedArray< u8 > {
        let vec: Vec< _ > = array.to_vec().into_iter().map( |value| value + 1 ).collect();
        vec.as_slice().into()
    }

    #[derive(Serialize, Deserialize)]
    pub struct Structure {
        field: i32
    }

    js_serializable!( Structure );
    js_deserializable!( Structure );

    #[js_export]
    fn structure_to_structure( structure: Structure ) -> Structure {
        Structure { field: structure.field + 1 }
    }

    #[derive(Serialize, Deserialize)]
    pub struct PlainStructure {
        field: i32
    }

    #[js_export]
    fn serde_structure_to_serde_structure( structure: Serde< PlainStructure > ) -> Serde< PlainStructure > {
        Serde( PlainStructure { field: structure.0.field + 1 } )
    }
}

pub fn run() {
    test( "i8_to_i8", || { js! { assert.strictEqual( Module.exports.i8_to_i8( 33 ), 34 ); }});
    test( "i16_to_i16", || { js! { assert.strictEqual( Module.exports.i16_to_i16( 33 ), 34 ); }});
    test( "i32_to_i32", || { js! { assert.strictEqual( Module.exports.i32_to_i32( 33 ), 34 ); }});
    test( "u8_to_u8", || { js! { assert.strictEqual( Module.exports.u8_to_u8( 33 ), 34 ); }});
    test( "u16_to_ui6", || { js! { assert.strictEqual( Module.exports.u16_to_u16( 33 ), 34 ); }});
    test( "u32_to_u32", || { js! { assert.strictEqual( Module.exports.u32_to_u32( 33 ), 34 ); }});
    test( "f64_to_f64", || { js! { assert.strictEqual( Module.exports.f64_to_f64( 3.33 ), 6.66 ); }});

    test( "add_two_u32", || { js! { assert.strictEqual( Module.exports.add_two_u32( 123, 1000 ), 1123 ); }});

    test( "rstr_to_string", || { js! {
        assert.strictEqual( Module.exports.rstr_to_string( "ABC" ), "ABC..." );
    }});

    test( "string_to_string", || { js! {
        assert.strictEqual( Module.exports.string_to_string( "ABC" ), "ABC..." );
    }});

    test( "rstr", || { js! {
        assert.strictEqual( Module.exports.rstr(), "A string" );
    }});

    test( "join_two_strings", || { js! {
        assert.strictEqual( Module.exports.join_two_strings( "ABC", "DEFGH" ), "ABCDEFGH" );
    }});

    test( "bool_to_bool", || { js! {
        assert.strictEqual( Module.exports.bool_to_bool( true ), false );
        assert.strictEqual( Module.exports.bool_to_bool( false ), true );
    }});

    test( "vec_to_vec", || { js! {
        assert.deepEqual( Module.exports.vec_to_vec( [ 1, 2, 3 ] ), [ 2, 3, 4 ] );
    }});

    test( "slice_to_vec", || { js! {
        assert.deepEqual( Module.exports.slice_to_vec( [ 1, 2, 3 ] ), [ 2, 3, 4 ] );
    }});

    test( "slice", || { js! {
        assert.deepEqual( Module.exports.slice(), [ 1, 2, 3 ] );
    }});

    test( "typed_array_to_typed_array_identity", || { js! {
        let array_in = Uint8Array.from( [ 1, 2, 3 ] );
        let array_out = Module.exports.typed_array_to_typed_array_identity( array_in );
        assert.strictEqual( array_in, array_out );
    }});

    test( "typed_array_to_typed_array", || { js! {
        let array_in = Uint8Array.from( [ 1, 2, 3 ] );
        let array_out = Module.exports.typed_array_to_typed_array( array_in );
        assert.deepEqual( Array.from( array_in ), [ 1, 2, 3 ] );
        assert.deepEqual( Array.from( array_out ), [ 2, 3, 4 ] );
    }});

    test( "structure_to_structure", || { js! {
        let output = Module.exports.structure_to_structure( { field: 1 } );
        assert.deepEqual( output, { field: 2 } );
    }});

    test( "serde_structure_to_serde_structure", || { js! {
        let output = Module.exports.serde_structure_to_serde_structure( { field: 1 } );
        assert.deepEqual( output, { field: 2 } );
    }});
}
<|endoftext|>