<commit_before>#![allow(unused, missing_docs)]

use std::fmt;
use std::iter::repeat;
use elements::{BlockType, External, FunctionType, GlobalEntry, GlobalType, Internal, MemoryType,
               Module, Opcode, ResizableLimits, TableType, Type, ValueType};
use common::stack;
use self::context::ModuleContext;
use self::func::Validator;

pub use self::module::ValidatedModule;

mod context;
mod module;
mod func;

#[cfg(test)]
mod tests;

pub struct Error(String);

impl fmt::Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "{}", self.0)
	}
}

impl From<stack::Error> for Error {
	fn from(e: stack::Error) -> Error {
		Error(format!("Stack: {}", e))
	}
}

pub fn validate_module(module: &Module) -> Result<ValidatedModule, Error> {
	let context = prepare_context(module)?;

	let function_section_len = module
		.function_section()
		.map(|s| s.entries().len())
		.unwrap_or(0);
	let code_section_len = module.code_section().map(|s| s.bodies().len()).unwrap_or(0);
	if function_section_len != code_section_len {
		return Err(Error(format!(
			"length of function section is {}, while len of code section is {}",
			function_section_len,
			code_section_len
		)));
	}

	// validate every function body in user modules
	if function_section_len != 0 {
		// tests use invalid code
		let function_section = module
			.function_section()
			.expect("function_section_len != 0; qed");
		let code_section = module
			.code_section()
			.expect("function_section_len != 0; function_section_len == code_section_len; qed");
		// check every function body
		for (index, function) in function_section.entries().iter().enumerate() {
			let function_body = code_section
				.bodies()
				.get(index as usize)
				.ok_or(Error(format!("Missing body for function {}", index)))?;
			Validator::validate_function(&context, function, function_body).map_err(|e| {
				let Error(ref msg) = e;
				Error(format!("Function #{} validation error: {}", index, msg))
			})?;
		}
	}

	// validate start section
	if let Some(start_function) = module.start_section() {
		let (params, return_ty) = context.require_function(start_function)?;
		if return_ty != BlockType::NoResult || params.len() != 0 {
			return Err(Error(
				"start function expected to have type [] -> []".into(),
			));
		}
	}

	// validate export section
	if let Some(export_section) = module.export_section() {
		for export in export_section.entries() {
			match export.internal() {
				&Internal::Function(function_index) => {
					context.require_function(function_index)?;
				}
				&Internal::Global(global_index) => {
					context.require_global(global_index, Some(false))?;
				}
				&Internal::Memory(memory_index) => {
					context.require_memory(memory_index)?;
				}
				&Internal::Table(table_index) => {
					context.require_table(table_index)?;
				}
			}
		}
	}

	// validate import section
	if let Some(import_section) = module.import_section() {
		for import in import_section.entries() {
			match import.external() {
				&External::Function(function_type_index) => {
					context.require_function(function_type_index)?;
				},
				&External::Global(ref global_type) => {
					if global_type.is_mutable() {
						return Err(Error(format!("trying to import mutable global {}", import.field())));
					}
				},
				&External::Memory(ref memory_type) => {
					memory_type.validate()?;
				},
				&External::Table(ref table_type) => {
					table_type.validate()?;
				},
			}
		}
	}

	// there must be no greater than 1 table in tables index space
	if context.tables().len() > 1 {
		return Err(Error(format!("too many tables in index space: {}", context.tables().len())));
	}

	// there must be no greater than 1 linear memory in memory index space
	if context.memories().len() > 1 {
		return Err(Error(format!("too many memory regions in index space: {}", context.memories().len())));
	}

	// TODO: data section
	// TODO: element section

	let ModuleContext {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	} = context;

	Ok(ValidatedModule {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	})
}

fn prepare_context(module: &Module) -> Result<ModuleContext, Error> {
	// Copy types from module as is.
	let types = module
		.type_section()
		.map(|ts| ts.types().into_iter().cloned().collect())
		.unwrap_or_default();

	// Fill elements with imported values.

	// TODO: Use Func::type_ref?
	let mut func_type_indexes = Vec::new();
	let mut tables = Vec::new();
	let mut memories = Vec::new();
	let mut globals = Vec::new();

	for import_entry in module
		.import_section()
		.map(|i| i.entries())
		.unwrap_or_default()
	{
		match import_entry.external() {
			&External::Function(idx) => func_type_indexes.push(idx),
			&External::Table(ref table) => tables.push(table.clone()),
			&External::Memory(ref memory) => memories.push(memory.clone()),
			&External::Global(ref global) => globals.push(global.clone()),
		}
	}

	// Concatenate elements with defined in the module.
	if let Some(function_section) = module.function_section() {
		for func_entry in function_section.entries() {
			func_type_indexes.push(func_entry.type_ref());
		}
	}
	if let Some(table_section) = module.table_section() {
		for table_entry in table_section.entries() {
			table_entry.validate()?;
			tables.push(table_entry.clone());
		}
	}
	if let Some(mem_section) = module.memory_section() {
		for mem_entry in mem_section.entries() {
			mem_entry.validate()?;
			memories.push(mem_entry.clone());
		}
	}
	if let Some(global_section) = module.global_section() {
		// Validation of globals is defined over modified context C', which
		// contains only imported globals. So we do globals validation
		// in two passes, in first we validate globals and after all globals are validated
		// add them in globals list.
		for global_entry in global_section.entries() {
			global_entry.validate(&globals)?;
		}

		for global_entry in global_section.entries() {
			globals.push(global_entry.global_type().clone());
		}
	}

	Ok(ModuleContext {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	})
}

impl ResizableLimits {
	fn validate(&self) -> Result<(), Error> {
		if let Some(maximum) = self.maximum() {
			if self.initial() > maximum {
				return Err(Error(format!(
					"maximum limit {} is lesser than minimum {}",
					maximum,
					self.initial()
				)));
			}
		}
		Ok(())
	}
}

impl MemoryType {
	fn validate(&self) -> Result<(), Error> {
		self.limits().validate()
	}
}

impl TableType {
	fn validate(&self) -> Result<(), Error> {
		self.limits().validate()
	}
}

impl GlobalEntry {
	fn validate(&self, globals_sofar: &[GlobalType]) -> Result<(), Error> {
		let init = self.init_expr().code();
		if init.len() != 2 {
			return Err(Error(
				format!("Init expression should always be with length 2"),
			));
		}
		let init_expr_ty: ValueType = match init[0] {
			Opcode::I32Const(_) => ValueType::I32,
			Opcode::I64Const(_) => ValueType::I64,
			Opcode::F32Const(_) => ValueType::F32,
			Opcode::F64Const(_) => ValueType::F64,
			Opcode::GetGlobal(idx) => match globals_sofar.get(idx as usize) {
				Some(target_global) => {
					if target_global.is_mutable() {
						return Err(Error(format!("Global {} is mutable", idx)));
					}
					target_global.content_type()
				}
				None => {
					return Err(Error(
						format!("Global {} doesn't exists or not yet defined", idx),
					))
				}
			},
			_ => return Err(Error(format!("Non constant opcode in init expr"))),
		};
		if init_expr_ty != self.global_type().content_type() {
			return Err(Error(format!(
				"Trying to initialize variable of type {:?} with value of type {:?}",
				self.global_type().content_type(),
				init_expr_ty
			)));
		}
		if init[1] != Opcode::End {
			return Err(Error(format!("Expression doesn't ends with `end` opcode")));
		}
		Ok(())
	}
}
<commit_msg>Refactor<commit_after>#![allow(unused, missing_docs)]

use std::fmt;
use std::iter::repeat;
use elements::{BlockType, External, FunctionType, GlobalEntry, GlobalType, Internal, MemoryType,
               Module, Opcode, ResizableLimits, TableType, Type, ValueType, InitExpr};
use common::stack;
use self::context::ModuleContext;
use self::func::Validator;

pub use self::module::ValidatedModule;

mod context;
mod module;
mod func;

#[cfg(test)]
mod tests;

pub struct Error(String);

impl fmt::Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "{}", self.0)
	}
}

impl From<stack::Error> for Error {
	fn from(e: stack::Error) -> Error {
		Error(format!("Stack: {}", e))
	}
}

pub fn validate_module(module: &Module) -> Result<ValidatedModule, Error> {
	let context = prepare_context(module)?;

	let function_section_len = module
		.function_section()
		.map(|s| s.entries().len())
		.unwrap_or(0);
	let code_section_len = module.code_section().map(|s| s.bodies().len()).unwrap_or(0);
	if function_section_len != code_section_len {
		return Err(Error(format!(
			"length of function section is {}, while len of code section is {}",
			function_section_len,
			code_section_len
		)));
	}

	// validate every function body in user modules
	if function_section_len != 0 {
		// tests use invalid code
		let function_section = module
			.function_section()
			.expect("function_section_len != 0; qed");
		let code_section = module
			.code_section()
			.expect("function_section_len != 0; function_section_len == code_section_len; qed");
		// check every function body
		for (index, function) in function_section.entries().iter().enumerate() {
			let function_body = code_section
				.bodies()
				.get(index as usize)
				.ok_or(Error(format!("Missing body for function {}", index)))?;
			Validator::validate_function(&context, function, function_body).map_err(|e| {
				let Error(ref msg) = e;
				Error(format!("Function #{} validation error: {}", index, msg))
			})?;
		}
	}

	// validate start section
	if let Some(start_function) = module.start_section() {
		let (params, return_ty) = context.require_function(start_function)?;
		if return_ty != BlockType::NoResult || params.len() != 0 {
			return Err(Error(
				"start function expected to have type [] -> []".into(),
			));
		}
	}

	// validate export section
	if let Some(export_section) = module.export_section() {
		for export in export_section.entries() {
			match export.internal() {
				&Internal::Function(function_index) => {
					context.require_function(function_index)?;
				}
				&Internal::Global(global_index) => {
					context.require_global(global_index, Some(false))?;
				}
				&Internal::Memory(memory_index) => {
					context.require_memory(memory_index)?;
				}
				&Internal::Table(table_index) => {
					context.require_table(table_index)?;
				}
			}
		}
	}

	// validate import section
	if let Some(import_section) = module.import_section() {
		for import in import_section.entries() {
			match import.external() {
				&External::Function(function_type_index) => {
					context.require_function(function_type_index)?;
				},
				&External::Global(ref global_type) => {
					if global_type.is_mutable() {
						return Err(Error(format!("trying to import mutable global {}", import.field())));
					}
				},
				&External::Memory(ref memory_type) => {
					memory_type.validate()?;
				},
				&External::Table(ref table_type) => {
					table_type.validate()?;
				},
			}
		}
	}

	// there must be no greater than 1 table in tables index space
	if context.tables().len() > 1 {
		return Err(Error(format!("too many tables in index space: {}", context.tables().len())));
	}

	// there must be no greater than 1 linear memory in memory index space
	if context.memories().len() > 1 {
		return Err(Error(format!("too many memory regions in index space: {}", context.memories().len())));
	}

	// TODO: data section
	// TODO: element section

	let ModuleContext {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	} = context;

	Ok(ValidatedModule {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	})
}

fn prepare_context(module: &Module) -> Result<ModuleContext, Error> {
	// Copy types from module as is.
	let types = module
		.type_section()
		.map(|ts| ts.types().into_iter().cloned().collect())
		.unwrap_or_default();

	// Fill elements with imported values.

	// TODO: Use Func::type_ref?
	let mut func_type_indexes = Vec::new();
	let mut tables = Vec::new();
	let mut memories = Vec::new();
	let mut globals = Vec::new();

	for import_entry in module
		.import_section()
		.map(|i| i.entries())
		.unwrap_or_default()
	{
		match import_entry.external() {
			&External::Function(idx) => func_type_indexes.push(idx),
			&External::Table(ref table) => tables.push(table.clone()),
			&External::Memory(ref memory) => memories.push(memory.clone()),
			&External::Global(ref global) => globals.push(global.clone()),
		}
	}

	// Concatenate elements with defined in the module.
	if let Some(function_section) = module.function_section() {
		for func_entry in function_section.entries() {
			func_type_indexes.push(func_entry.type_ref());
		}
	}
	if let Some(table_section) = module.table_section() {
		for table_entry in table_section.entries() {
			table_entry.validate()?;
			tables.push(table_entry.clone());
		}
	}
	if let Some(mem_section) = module.memory_section() {
		for mem_entry in mem_section.entries() {
			mem_entry.validate()?;
			memories.push(mem_entry.clone());
		}
	}
	if let Some(global_section) = module.global_section() {
		// Validation of globals is defined over modified context C', which
		// contains only imported globals. So we do globals validation
		// in two passes, in first we validate globals and after all globals are validated
		// add them in globals list.
		for global_entry in global_section.entries() {
			global_entry.validate(&globals)?;
		}

		for global_entry in global_section.entries() {
			globals.push(global_entry.global_type().clone());
		}
	}

	Ok(ModuleContext {
		types,
		tables,
		memories,
		globals,
		func_type_indexes,
	})
}

impl ResizableLimits {
	fn validate(&self) -> Result<(), Error> {
		if let Some(maximum) = self.maximum() {
			if self.initial() > maximum {
				return Err(Error(format!(
					"maximum limit {} is lesser than minimum {}",
					maximum,
					self.initial()
				)));
			}
		}
		Ok(())
	}
}

impl MemoryType {
	fn validate(&self) -> Result<(), Error> {
		self.limits().validate()
	}
}

impl TableType {
	fn validate(&self) -> Result<(), Error> {
		self.limits().validate()
	}
}

impl GlobalEntry {
	fn validate(&self, globals: &[GlobalType]) -> Result<(), Error> {
		let init = self.init_expr();
		init.validate(globals)?;
		let init_expr_ty = init.expr_const_type(globals)?;
		if init_expr_ty != self.global_type().content_type() {
			return Err(Error(format!(
				"Trying to initialize variable of type {:?} with value of type {:?}",
				self.global_type().content_type(),
				init_expr_ty
			)));
		}
		Ok(())
	}
}

impl InitExpr {
	fn validate(&self, globals: &[GlobalType]) -> Result<(), Error> {
		let code = self.code();
		if code.len() != 2 {
			return Err(Error(
				format!("Init expression should always be with length 2"),
			));
		}
		let _ = self.expr_const_type(globals)?;
		if code[1] != Opcode::End {
			return Err(Error(format!("Expression doesn't ends with `end` opcode")));
		}
		Ok(())
	}

	fn expr_const_type(&self, globals: &[GlobalType]) -> Result<ValueType, Error> {
		let code = self.code();
		let expr_ty: ValueType = match code[0] {
			Opcode::I32Const(_) => ValueType::I32,
			Opcode::I64Const(_) => ValueType::I64,
			Opcode::F32Const(_) => ValueType::F32,
			Opcode::F64Const(_) => ValueType::F64,
			Opcode::GetGlobal(idx) => match globals.get(idx as usize) {
				Some(target_global) => {
					if target_global.is_mutable() {
						return Err(Error(format!("Global {} is mutable", idx)));
					}
					target_global.content_type()
				}
				None => {
					return Err(Error(
						format!("Global {} doesn't exists or not yet defined", idx),
					))
				}
			},
			_ => return Err(Error(format!("Non constant opcode in init expr"))),
		};
		Ok(expr_ty)
	}
}
<|endoftext|>


<commit_before><commit_msg>Front: Rewrite check_void_var to use ast::Visitor<commit_after><|endoftext|>


<commit_before>/**
 * Exponential Functions
 *
 * This module corresponds to Section 8.2 of the [GLSL 4.30.6 specification]
 * (http://www.opengl.org/registry/doc/GLSLangSpec.4.30.6.pdf).
 */

use num::cast::{NumCast, cast};
use vec::{Vec2, Vec3, Vec4};

pub trait Exp {
    pure fn pow(&self, n: &self) -> self;
    pure fn exp(&self)      -> self;
    pure fn log_(&self)     -> self;
    pure fn exp2(&self)     -> self;
    pure fn log2(&self)     -> self;
    pure fn sqrt(&self)     -> self;
    pure fn inv_sqrt(&self) -> self;
}

#[inline(always)] pub pure fn pow<T:Exp>(x: &T, n: &T)  -> T { x.pow(n) }
#[inline(always)] pub pure fn exp<T:Exp>(x: &T)         -> T { x.exp()  }
#[inline(always)] pub pure fn log_<T:Exp>(x: &T)        -> T { x.log_() }
#[inline(always)] pub pure fn exp2<T:Exp>(x: &T)        -> T { x.exp2() }
#[inline(always)] pub pure fn log2<T:Exp>(x: &T)        -> T { x.log2() }
#[inline(always)] pub pure fn sqrt<T:Exp>(x: &T)        -> T { x.sqrt() }
#[inline(always)] pub pure fn inv_sqrt<T:Exp>(x: &T)    -> T { x.inv_sqrt() }

pub impl f32: Exp {
    #[inline(always)] pure fn pow(&self, n: &f32)      -> f32 { cast(cmath::c_float_utils::pow(*self, n.cast())) }
    #[inline(always)] pure fn exp(&self)             -> f32 { cast(cmath::c_float_utils::exp(*self)) }
    #[inline(always)] pure fn log_(&self)            -> f32 { cast(cmath::c_float_utils::ln(*self)) }
    #[inline(always)] pure fn exp2(&self)            -> f32 { cast(cmath::c_float_utils::exp2(*self)) }
    #[inline(always)] pure fn log2(&self)            -> f32 { cast(cmath::c_float_utils::log2(*self)) }
    #[inline(always)] pure fn sqrt(&self)            -> f32 { cast(cmath::c_float_utils::sqrt(*self)) }
    #[inline(always)] pure fn inv_sqrt(&self)        -> f32 { 1f32 / self.sqrt() }  // TODO: optimise? need a wizard
}

pub impl f64: Exp {
    #[inline(always)] pure fn pow(&self, n: &f64)      -> f64 { cast(cmath::c_double_utils::pow(*self, n.cast())) }
    #[inline(always)] pure fn exp(&self)             -> f64 { cast(cmath::c_double_utils::exp(*self)) }
    #[inline(always)] pure fn log_(&self)            -> f64 { cast(cmath::c_double_utils::ln(*self)) }
    #[inline(always)] pure fn exp2(&self)            -> f64 { cast(cmath::c_double_utils::exp2(*self)) }
    #[inline(always)] pure fn log2(&self)            -> f64 { cast(cmath::c_double_utils::log2(*self)) }
    #[inline(always)] pure fn sqrt(&self)            -> f64 { cast(cmath::c_double_utils::sqrt(*self)) }
    #[inline(always)] pure fn inv_sqrt(&self)        -> f64 { 1f64 / self.sqrt() }  // TODO: optimise? need a wizard
}

pub impl float: Exp {
    #[inline(always)] pure fn pow(&self, n: &float)    -> float { cast(cmath::c_float_utils::pow(cast(*self), n.cast())) }
    #[inline(always)] pure fn exp(&self)             -> float { cast(cmath::c_float_utils::exp(cast(*self))) }
    #[inline(always)] pure fn log_(&self)            -> float { cast(cmath::c_float_utils::ln(cast(*self))) }
    #[inline(always)] pure fn exp2(&self)            -> float { cast(cmath::c_float_utils::exp2(cast(*self))) }
    #[inline(always)] pure fn log2(&self)            -> float { cast(cmath::c_float_utils::log2(cast(*self))) }
    #[inline(always)] pure fn sqrt(&self)            -> float { cast(cmath::c_float_utils::sqrt(cast(*self))) }
    #[inline(always)] pure fn inv_sqrt(&self)        -> float { 1f / self.sqrt() }  // TODO: optimise? need a wizard
}

pub impl<T:Copy Exp> Vec2<T>: Exp {
    #[inline(always)]
    pure fn pow(&self, n: &Vec2<T>) -> Vec2<T> {
        Vec2::new(pow(&self[0], &n[0]),
                  pow(&self[1], &n[1]))
    }

    #[inline(always)]
    pure fn exp(&self) -> Vec2<T> {
        Vec2::new(exp(&self[0]),
                  exp(&self[1]))
    }

    #[inline(always)]
    pure fn log_(&self) -> Vec2<T> {
        Vec2::new(log_(&self[0]),
                  log_(&self[1]))
    }

    #[inline(always)]
    pure fn exp2(&self) -> Vec2<T> {
        Vec2::new(exp2(&self[0]),
                  exp2(&self[1]))
    }

    #[inline(always)]
    pure fn log2(&self) -> Vec2<T> {
        Vec2::new(log2(&self[0]),
                  log2(&self[1]))
    }

    #[inline(always)]
    pure fn sqrt(&self) -> Vec2<T> {
        Vec2::new(sqrt(&self[0]),
                  sqrt(&self[1]))
    }

    #[inline(always)]
    pure fn inv_sqrt(&self) -> Vec2<T> {
        Vec2::new(inv_sqrt(&self[0]),
                  inv_sqrt(&self[1]))
    }
}

pub impl<T:Copy Exp> Vec3<T>: Exp {
    #[inline(always)]
    pure fn pow(&self, n: &Vec3<T>) -> Vec3<T> {
        Vec3::new(pow(&self[0], &n[0]),
                  pow(&self[1], &n[1]),
                  pow(&self[2], &n[2]))
    }

    #[inline(always)]
    pure fn exp(&self) -> Vec3<T> {
        Vec3::new(exp(&self[0]),
                  exp(&self[1]),
                  exp(&self[2]))
    }

    #[inline(always)]
    pure fn log_(&self) -> Vec3<T> {
        Vec3::new(log_(&self[0]),
                  log_(&self[1]),
                  log_(&self[2]))
    }

    #[inline(always)]
    pure fn exp2(&self) -> Vec3<T> {
        Vec3::new(exp2(&self[0]),
                  exp2(&self[1]),
                  exp2(&self[2]))
    }

    #[inline(always)]
    pure fn log2(&self) -> Vec3<T> {
        Vec3::new(log2(&self[0]),
                  log2(&self[1]),
                  log2(&self[2]))
    }

    #[inline(always)]
    pure fn sqrt(&self) -> Vec3<T> {
        Vec3::new(sqrt(&self[0]),
                  sqrt(&self[1]),
                  sqrt(&self[2]))
    }

    #[inline(always)]
    pure fn inv_sqrt(&self) -> Vec3<T> {
        Vec3::new(inv_sqrt(&self[0]),
                  inv_sqrt(&self[1]),
                  inv_sqrt(&self[2]))
    }
}

pub impl<T:Copy Exp> Vec4<T>: Exp {
    #[inline(always)]
    pure fn pow(&self, n: &Vec4<T>) -> Vec4<T> {
        Vec4::new(pow(&self[0], &n[0]),
                  pow(&self[1], &n[1]),
                  pow(&self[2], &n[2]),
                  pow(&self[3], &n[3]))
    }

    #[inline(always)]
    pure fn exp(&self) -> Vec4<T> {
        Vec4::new(exp(&self[0]),
                  exp(&self[1]),
                  exp(&self[2]),
                  exp(&self[3]))
    }

    #[inline(always)]
    pure fn log_(&self) -> Vec4<T> {
        Vec4::new(log_(&self[0]),
                  log_(&self[1]),
                  log_(&self[2]),
                  log_(&self[3]))
    }

    #[inline(always)]
    pure fn exp2(&self) -> Vec4<T> {
        Vec4::new(exp2(&self[0]),
                  exp2(&self[1]),
                  exp2(&self[2]),
                  exp2(&self[3]))
    }

    #[inline(always)]
    pure fn log2(&self) -> Vec4<T> {
        Vec4::new(log2(&self[0]),
                  log2(&self[1]),
                  log2(&self[2]),
                  log2(&self[3]))
    }

    #[inline(always)]
    pure fn sqrt(&self) -> Vec4<T> {
        Vec4::new(sqrt(&self[0]),
                  sqrt(&self[1]),
                  sqrt(&self[2]),
                  sqrt(&self[3]))
    }

    #[inline(always)]
    pure fn inv_sqrt(&self) -> Vec4<T> {
        Vec4::new(inv_sqrt(&self[0]),
                  inv_sqrt(&self[1]),
                  inv_sqrt(&self[2]),
                  inv_sqrt(&self[3]))
    }
}<commit_msg>Formatting<commit_after>/**
 * Exponential Functions
 *
 * This module corresponds to Section 8.2 of the [GLSL 4.30.6 specification]
 * (http://www.opengl.org/registry/doc/GLSLangSpec.4.30.6.pdf).
 */

use num::cast::{NumCast, cast};
use vec::{Vec2, Vec3, Vec4};

pub trait Exp {
    pure fn pow(&self, n: &self) -> self;
    pure fn exp(&self)      -> self;
    pure fn log_(&self)     -> self;
    pure fn exp2(&self)     -> self;
    pure fn log2(&self)     -> self;
    pure fn sqrt(&self)     -> self;
    pure fn inv_sqrt(&self) -> self;
}

#[inline(always)] pub pure fn pow<T:Exp>(x: &T, n: &T)  -> T { x.pow(n) }
#[inline(always)] pub pure fn exp<T:Exp>(x: &T)         -> T { x.exp()  }
#[inline(always)] pub pure fn log_<T:Exp>(x: &T)        -> T { x.log_() }
#[inline(always)] pub pure fn exp2<T:Exp>(x: &T)        -> T { x.exp2() }
#[inline(always)] pub pure fn log2<T:Exp>(x: &T)        -> T { x.log2() }
#[inline(always)] pub pure fn sqrt<T:Exp>(x: &T)        -> T { x.sqrt() }
#[inline(always)] pub pure fn inv_sqrt<T:Exp>(x: &T)    -> T { x.inv_sqrt() }

pub impl f32: Exp {
    #[inline(always)] pure fn pow(&self, n: &f32)    -> f32 { cast(cmath::c_float_utils::pow(*self, n.cast())) }
    #[inline(always)] pure fn exp(&self)             -> f32 { cast(cmath::c_float_utils::exp(*self)) }
    #[inline(always)] pure fn log_(&self)            -> f32 { cast(cmath::c_float_utils::ln(*self)) }
    #[inline(always)] pure fn exp2(&self)            -> f32 { cast(cmath::c_float_utils::exp2(*self)) }
    #[inline(always)] pure fn log2(&self)            -> f32 { cast(cmath::c_float_utils::log2(*self)) }
    #[inline(always)] pure fn sqrt(&self)            -> f32 { cast(cmath::c_float_utils::sqrt(*self)) }
    #[inline(always)] pure fn inv_sqrt(&self)        -> f32 { 1f32 / self.sqrt() }  // TODO: optimise? need a wizard
}

pub impl f64: Exp {
    #[inline(always)] pure fn pow(&self, n: &f64)    -> f64 { cast(cmath::c_double_utils::pow(*self, n.cast())) }
    #[inline(always)] pure fn exp(&self)             -> f64 { cast(cmath::c_double_utils::exp(*self)) }
    #[inline(always)] pure fn log_(&self)            -> f64 { cast(cmath::c_double_utils::ln(*self)) }
    #[inline(always)] pure fn exp2(&self)            -> f64 { cast(cmath::c_double_utils::exp2(*self)) }
    #[inline(always)] pure fn log2(&self)            -> f64 { cast(cmath::c_double_utils::log2(*self)) }
    #[inline(always)] pure fn sqrt(&self)            -> f64 { cast(cmath::c_double_utils::sqrt(*self)) }
    #[inline(always)] pure fn inv_sqrt(&self)        -> f64 { 1f64 / self.sqrt() }  // TODO: optimise? need a wizard
}

pub impl float: Exp {
    #[inline(always)] pure fn pow(&self, n: &float)  -> float { cast(cmath::c_float_utils::pow(cast(*self), n.cast())) }
    #[inline(always)] pure fn exp(&self)             -> float { cast(cmath::c_float_utils::exp(cast(*self))) }
    #[inline(always)] pure fn log_(&self)            -> float { cast(cmath::c_float_utils::ln(cast(*self))) }
    #[inline(always)] pure fn exp2(&self)            -> float { cast(cmath::c_float_utils::exp2(cast(*self))) }
    #[inline(always)] pure fn log2(&self)            -> float { cast(cmath::c_float_utils::log2(cast(*self))) }
    #[inline(always)] pure fn sqrt(&self)            -> float { cast(cmath::c_float_utils::sqrt(cast(*self))) }
    #[inline(always)] pure fn inv_sqrt(&self)        -> float { 1f / self.sqrt() }  // TODO: optimise? need a wizard
}

pub impl<T:Copy Exp> Vec2<T>: Exp {
    #[inline(always)]
    pure fn pow(&self, n: &Vec2<T>) -> Vec2<T> {
        Vec2::new(pow(&self[0], &n[0]),
                  pow(&self[1], &n[1]))
    }

    #[inline(always)]
    pure fn exp(&self) -> Vec2<T> {
        Vec2::new(exp(&self[0]),
                  exp(&self[1]))
    }

    #[inline(always)]
    pure fn log_(&self) -> Vec2<T> {
        Vec2::new(log_(&self[0]),
                  log_(&self[1]))
    }

    #[inline(always)]
    pure fn exp2(&self) -> Vec2<T> {
        Vec2::new(exp2(&self[0]),
                  exp2(&self[1]))
    }

    #[inline(always)]
    pure fn log2(&self) -> Vec2<T> {
        Vec2::new(log2(&self[0]),
                  log2(&self[1]))
    }

    #[inline(always)]
    pure fn sqrt(&self) -> Vec2<T> {
        Vec2::new(sqrt(&self[0]),
                  sqrt(&self[1]))
    }

    #[inline(always)]
    pure fn inv_sqrt(&self) -> Vec2<T> {
        Vec2::new(inv_sqrt(&self[0]),
                  inv_sqrt(&self[1]))
    }
}

pub impl<T:Copy Exp> Vec3<T>: Exp {
    #[inline(always)]
    pure fn pow(&self, n: &Vec3<T>) -> Vec3<T> {
        Vec3::new(pow(&self[0], &n[0]),
                  pow(&self[1], &n[1]),
                  pow(&self[2], &n[2]))
    }

    #[inline(always)]
    pure fn exp(&self) -> Vec3<T> {
        Vec3::new(exp(&self[0]),
                  exp(&self[1]),
                  exp(&self[2]))
    }

    #[inline(always)]
    pure fn log_(&self) -> Vec3<T> {
        Vec3::new(log_(&self[0]),
                  log_(&self[1]),
                  log_(&self[2]))
    }

    #[inline(always)]
    pure fn exp2(&self) -> Vec3<T> {
        Vec3::new(exp2(&self[0]),
                  exp2(&self[1]),
                  exp2(&self[2]))
    }

    #[inline(always)]
    pure fn log2(&self) -> Vec3<T> {
        Vec3::new(log2(&self[0]),
                  log2(&self[1]),
                  log2(&self[2]))
    }

    #[inline(always)]
    pure fn sqrt(&self) -> Vec3<T> {
        Vec3::new(sqrt(&self[0]),
                  sqrt(&self[1]),
                  sqrt(&self[2]))
    }

    #[inline(always)]
    pure fn inv_sqrt(&self) -> Vec3<T> {
        Vec3::new(inv_sqrt(&self[0]),
                  inv_sqrt(&self[1]),
                  inv_sqrt(&self[2]))
    }
}

pub impl<T:Copy Exp> Vec4<T>: Exp {
    #[inline(always)]
    pure fn pow(&self, n: &Vec4<T>) -> Vec4<T> {
        Vec4::new(pow(&self[0], &n[0]),
                  pow(&self[1], &n[1]),
                  pow(&self[2], &n[2]),
                  pow(&self[3], &n[3]))
    }

    #[inline(always)]
    pure fn exp(&self) -> Vec4<T> {
        Vec4::new(exp(&self[0]),
                  exp(&self[1]),
                  exp(&self[2]),
                  exp(&self[3]))
    }

    #[inline(always)]
    pure fn log_(&self) -> Vec4<T> {
        Vec4::new(log_(&self[0]),
                  log_(&self[1]),
                  log_(&self[2]),
                  log_(&self[3]))
    }

    #[inline(always)]
    pure fn exp2(&self) -> Vec4<T> {
        Vec4::new(exp2(&self[0]),
                  exp2(&self[1]),
                  exp2(&self[2]),
                  exp2(&self[3]))
    }

    #[inline(always)]
    pure fn log2(&self) -> Vec4<T> {
        Vec4::new(log2(&self[0]),
                  log2(&self[1]),
                  log2(&self[2]),
                  log2(&self[3]))
    }

    #[inline(always)]
    pure fn sqrt(&self) -> Vec4<T> {
        Vec4::new(sqrt(&self[0]),
                  sqrt(&self[1]),
                  sqrt(&self[2]),
                  sqrt(&self[3]))
    }

    #[inline(always)]
    pure fn inv_sqrt(&self) -> Vec4<T> {
        Vec4::new(inv_sqrt(&self[0]),
                  inv_sqrt(&self[1]),
                  inv_sqrt(&self[2]),
                  inv_sqrt(&self[3]))
    }
}<|endoftext|>


<commit_before>#![feature(slice_concat_ext)]
#![feature(integer_atomics)]

extern crate imageflow_helpers;
extern crate imageflow_core as fc;
extern crate imageflow_types as s;
use ::imageflow_helpers::preludes::from_std::*;
extern crate hyper;

use std::slice::SliceConcatExt;

extern crate wait_timeout;
use wait_timeout::ChildExt;
use std::time::Duration;
use std::process::{Command, Stdio, Child,Output};

use ::imageflow_helpers::process_testing::*;
use fc::test_helpers::*;
use fc::test_helpers::process_testing::ProcTestContextExtras;
use fc::test_helpers::process_testing::ProcOutputExtras;
use ::imageflow_helpers::fetching::FetchError;
use ::imageflow_helpers::fetching::{fetch_bytes,get_status_code_for};
fn server_path() -> PathBuf{
    let self_path = std::env::current_exe().expect("For --self-test to work, we need to know the binary's location. env::current_exe failed");
    self_path.parent().unwrap().join("imageflow_server")
}

fn get_next_port() -> u16{
    use std::sync::atomic::{AtomicU16, Ordering, ATOMIC_U16_INIT};
    static NEXT_PORT: AtomicU16 = ATOMIC_U16_INIT;

    NEXT_PORT.compare_and_swap(0, 36203, Ordering::SeqCst);
    NEXT_PORT.fetch_add(1, Ordering::SeqCst)
}

struct ServerInstance{
    port: u16,
}

type CallbackResult = std::result::Result<(), ::imageflow_helpers::fetching::FetchError>;
impl ServerInstance{

    fn speaks_http(&self) -> bool{
        self.hello().is_ok()
    }

    fn hello(&self) -> std::result::Result<hyper::status::StatusCode, FetchError> {
        get_status_code_for(&self.url_for("/hello/are/you/running?"))
    }

    fn url_for(&self, rel_path: &str) -> String{
        format!("http://localhost:{}{}", self.port,rel_path)
    }

    fn get_status(&self, rel_path: &str) -> std::result::Result<hyper::status::StatusCode, FetchError> {
        get_status_code_for(&self.url_for(rel_path))
    }

    fn request_stop(&self) -> std::result::Result<hyper::status::StatusCode, FetchError> {
        get_status_code_for(&self.url_for("/test/shutdown"))
    }

    fn run<F>(c: &ProcTestContext, args: Vec<&str>, callback: F) -> (ProcOutput, CallbackResult)
    where F: Fn(&ServerInstance) -> CallbackResult {
        let instance = ServerInstance {
            port: get_next_port()
        };
        // NOTE --bind=localhost::{} (two colons) causes a generic "error:",exit code 1, and no other output. This is bad UX.
        let test_arg = "--integration-test";
        let port_arg = format!("--port={}", instance.port);
        let mut all_args = args.clone();
        all_args.insert(0, test_arg);
        all_args.insert(0, &port_arg);
        all_args.insert(0, "start");

        c.execute_callback(all_args, false,
                           |child: &mut std::process::Child| -> std::result::Result<(), ::imageflow_helpers::fetching::FetchError> {

                               ::std::thread::sleep_ms(500);
                               // Server may not be running
                               instance.hello()?;

                               let r = callback(&instance);

                               let _ = instance.request_stop();
                               r
                           })
        //po.expect_status_code(Some(0));
    }
}

// ports 36,000 to 39,999 seem the safest.
#[test]
fn run_server_test_i4(){

    let context = ProcTestContext::create_timestamp_subdir_within("server_tests", Some(server_path()));

    {
        let c = context.subfolder_context("basics");
        c.exec("diagnose --show-compilation-info").expect_status_code(Some(0));
        c.exec("--version").expect_status_code(Some(0));
        c.exec("-V").expect_status_code(Some(0));

        //TODO: test diagnose --call-panic (xplat hard)

        //Test incorrect args
        c.execute(vec!["demo"], false, |child: &mut std::process::Child| {
        }).expect_status_code(Some(1));

    }

    {
        let c = context.subfolder_context("demo"); //stuck on port 39876
        c.subfolder_context("demo");
        let (po, callback_result) = ServerInstance::run(&c, vec!["--demo", "--data-dir=."], | server | {
            fetch_bytes(&server.url_for("/ir4/proxy_unsplash/photo-1422493757035-1e5e03968f95?width=100"))?;
            assert_eq!(server.get_status("/ir4/proxy_unsplash/notthere.jpg")?, hyper::status::StatusCode::NotFound);
            Ok(())
        });

        //po.expect_status_code(Some(0));

        callback_result.unwrap();
    }
    {
        let c = context.subfolder_context("mount_local"); //stuck on port 39876
        c.create_blank_image_here("eh", 100,100, s::EncoderPreset::libpng32());
        let a = c.subfolder_context("a"); //stuck on port 39876
        a.create_blank_image_here("eh2", 100,100, s::EncoderPreset::libpng32());

        let mut params = vec!["--data-dir=.", "--mount=/local/:ir4_local:./",
                              "--mount=/local_1/:ir4_local:./a",
                              "--mount=/local_2/:ir4_local:./a/",
                              "--mount=/local_3/:ir4_local:a"];
        if std::path::MAIN_SEPARATOR == '\\'{
            params.push(r"--mount=/local_4/:ir4_local:.\a");
            params.push(r"--mount=/local_5/:ir4_local:.\a/");
            params.push(r"--mount=/local_5/:ir4_local:.\a\");
        }

        let last_mount = params.len() - 2;

        let (po, callback_result) = ServerInstance::run(&c, params , | server | {
            let bytes = fetch_bytes(&server.url_for("/local/eh.png?width=100")).unwrap();

            let info = fc::clients::stateless::LibClient {}.get_image_info(&bytes).expect("Image response should be valid");

            for ix in 1..last_mount + 1{

                let url = format!("/local_{ix}/eh2.png?w=1", ix=ix);
                println!("Testing {}", &url);
                let bytes = fetch_bytes(&server.url_for(&url)).unwrap();

                let info = fc::clients::stateless::LibClient {}.get_image_info(&bytes).expect("Image response should be valid");

                assert_eq!(server.get_status(&url)?, hyper::status::StatusCode::Ok);
            }

            assert_eq!(server.get_status("/local/notthere.jpg")?, hyper::status::StatusCode::NotFound);
            assert_eq!(server.get_status("/notrouted")?, hyper::status::StatusCode::NotFound);
            Ok(())
        });
        //po.expect_status_code(Some(0));

        callback_result.unwrap();
    }
}

trait ProcTestContextHttp{
 fn execute_callback<F,T>(&self, args_vec: Vec<&str>, valgrind_on_signal_death: bool, callback: F) -> (ProcOutput, T)
where F: Fn(&mut std::process::Child) -> T;

}
impl ProcTestContextHttp for ProcTestContext{

    ///
    /// Pass false for valgrind_on_signal_death if your callback might kill the child
    fn execute_callback<F,T>(&self, args_vec: Vec<&str>, valgrind_on_signal_death: bool, callback: F) -> (ProcOutput, T)
        where F: Fn(&mut std::process::Child) -> T {
        //TODO: serialize in a safer way - this isn't correct
        let full_invocation = format!("{} {}", &self.bin_location().to_str().unwrap(), args_vec.join(" "));

        let dir = self.working_dir();
        let exe = self.bin_location();

        let valgrind_copy_result = self.create_valgrind_suppressions();
        let _ = writeln!(&mut std::io::stderr(),
                         "Executing from folder {} with valgrind_suppressions {:?}\n{}",
                         dir.to_str().unwrap(),
                         valgrind_copy_result,
                         full_invocation);
        // change working dir to dir
        let mut cmd = Command::new(exe);
        cmd.args(args_vec.as_slice()).current_dir(dir).env("RUST_BACKTRACE", "1");

        //cmd.stderr(Stdio::piped()).stdout(Stdio::piped());
        cmd.stderr(Stdio::inherit()).stdout(Stdio::inherit());

        let mut child = cmd.spawn().expect("Failed to start?");

        let result = callback(&mut child);

        ///child.kill().unwrap();
        let timeout = Some(Duration::from_secs(1));

        let (status_code, output) = match timeout {
            Some(timeout) => {
                match child.wait_timeout(timeout).unwrap() {
                    Some(status) => (status.code(), None),
                    None => {
                        // child hasn't exited yet
                        child.kill().unwrap();
                        (child.wait().unwrap().code(), None)
                    }
                }
            }
            None => {
                let output: Output = child.wait_with_output().unwrap();
                (output.status.code(), Some(output))
            }
        };

        let _ = writeln!(&mut std::io::stderr(),
                         "exit code {:?}", status_code);

        // Double check we dumped output on segfault
        if status_code == None {
            if let Some(ref out) = output {
                std::io::stderr().write(&out.stderr).unwrap();
                std::io::stdout().write(&out.stdout).unwrap();
            }
            let _ = writeln!(&mut std::io::stderr(),
                             "exit code {:?}", status_code);
        }
        // Killed by signal.
        // 11 Segmentation fault
        // 4 illegal instruction 6 abort 8 floating point error
        if status_code == None && valgrind_on_signal_death {
            if std::env::var("VALGRIND_RUNNING").is_ok() {
                let _ = writeln!(&mut std::io::stderr(),
                                 "VALGRIND_RUNNING defined; skipping valgrind pass");
            } else {
                //ALLOW TO FAIL; valgrind may not be present
                let _ = writeln!(&mut std::io::stderr(),
                                 "Starting valgrind from within self-test:");
                let mut cmd = Command::new("valgrind");
                cmd.arg("-q").arg("--error-exitcode=9").arg(exe);
                cmd.args(args_vec.as_slice()).current_dir(dir).env("RUST_BACKTRACE", "1").env("VALGRIND_RUNNING", "1");

                let _ = writeln!(&mut std::io::stderr(),
                                 "{:?}", cmd);

                let _ = cmd.status(); //.expect("Failed to start valgrind?");
            }
        }

        match output {
            Some(out) => (ProcOutput::from(out), result),
            None => (ProcOutput::from_code(status_code), result)
        }
    }

}<commit_msg>ir4_tests: fix a windows-only test prefix<commit_after>#![feature(slice_concat_ext)]
#![feature(integer_atomics)]

extern crate imageflow_helpers;
extern crate imageflow_core as fc;
extern crate imageflow_types as s;
use ::imageflow_helpers::preludes::from_std::*;
extern crate hyper;

use std::slice::SliceConcatExt;

extern crate wait_timeout;
use wait_timeout::ChildExt;
use std::time::Duration;
use std::process::{Command, Stdio, Child,Output};

use ::imageflow_helpers::process_testing::*;
use fc::test_helpers::*;
use fc::test_helpers::process_testing::ProcTestContextExtras;
use fc::test_helpers::process_testing::ProcOutputExtras;
use ::imageflow_helpers::fetching::FetchError;
use ::imageflow_helpers::fetching::{fetch_bytes,get_status_code_for};
fn server_path() -> PathBuf{
    let self_path = std::env::current_exe().expect("For --self-test to work, we need to know the binary's location. env::current_exe failed");
    self_path.parent().unwrap().join("imageflow_server")
}

fn get_next_port() -> u16{
    use std::sync::atomic::{AtomicU16, Ordering, ATOMIC_U16_INIT};
    static NEXT_PORT: AtomicU16 = ATOMIC_U16_INIT;

    NEXT_PORT.compare_and_swap(0, 36203, Ordering::SeqCst);
    NEXT_PORT.fetch_add(1, Ordering::SeqCst)
}

struct ServerInstance{
    port: u16,
}

type CallbackResult = std::result::Result<(), ::imageflow_helpers::fetching::FetchError>;
impl ServerInstance{

    fn speaks_http(&self) -> bool{
        self.hello().is_ok()
    }

    fn hello(&self) -> std::result::Result<hyper::status::StatusCode, FetchError> {
        get_status_code_for(&self.url_for("/hello/are/you/running?"))
    }

    fn url_for(&self, rel_path: &str) -> String{
        format!("http://localhost:{}{}", self.port,rel_path)
    }

    fn get_status(&self, rel_path: &str) -> std::result::Result<hyper::status::StatusCode, FetchError> {
        get_status_code_for(&self.url_for(rel_path))
    }

    fn request_stop(&self) -> std::result::Result<hyper::status::StatusCode, FetchError> {
        get_status_code_for(&self.url_for("/test/shutdown"))
    }

    fn run<F>(c: &ProcTestContext, args: Vec<&str>, callback: F) -> (ProcOutput, CallbackResult)
    where F: Fn(&ServerInstance) -> CallbackResult {
        let instance = ServerInstance {
            port: get_next_port()
        };
        // NOTE --bind=localhost::{} (two colons) causes a generic "error:",exit code 1, and no other output. This is bad UX.
        let test_arg = "--integration-test";
        let port_arg = format!("--port={}", instance.port);
        let mut all_args = args.clone();
        all_args.insert(0, test_arg);
        all_args.insert(0, &port_arg);
        all_args.insert(0, "start");

        c.execute_callback(all_args, false,
                           |child: &mut std::process::Child| -> std::result::Result<(), ::imageflow_helpers::fetching::FetchError> {

                               ::std::thread::sleep_ms(500);
                               // Server may not be running
                               instance.hello()?;

                               let r = callback(&instance);

                               let _ = instance.request_stop();
                               r
                           })
        //po.expect_status_code(Some(0));
    }
}

// ports 36,000 to 39,999 seem the safest.
#[test]
fn run_server_test_i4(){

    let context = ProcTestContext::create_timestamp_subdir_within("server_tests", Some(server_path()));

    {
        let c = context.subfolder_context("basics");
        c.exec("diagnose --show-compilation-info").expect_status_code(Some(0));
        c.exec("--version").expect_status_code(Some(0));
        c.exec("-V").expect_status_code(Some(0));

        //TODO: test diagnose --call-panic (xplat hard)

        //Test incorrect args
        c.execute(vec!["demo"], false, |child: &mut std::process::Child| {
        }).expect_status_code(Some(1));

    }

    {
        let c = context.subfolder_context("demo"); //stuck on port 39876
        c.subfolder_context("demo");
        let (po, callback_result) = ServerInstance::run(&c, vec!["--demo", "--data-dir=."], | server | {
            fetch_bytes(&server.url_for("/ir4/proxy_unsplash/photo-1422493757035-1e5e03968f95?width=100"))?;
            assert_eq!(server.get_status("/ir4/proxy_unsplash/notthere.jpg")?, hyper::status::StatusCode::NotFound);
            Ok(())
        });

        //po.expect_status_code(Some(0));

        callback_result.unwrap();
    }
    {
        let c = context.subfolder_context("mount_local"); //stuck on port 39876
        c.create_blank_image_here("eh", 100,100, s::EncoderPreset::libpng32());
        let a = c.subfolder_context("a"); //stuck on port 39876
        a.create_blank_image_here("eh2", 100,100, s::EncoderPreset::libpng32());

        let mut params = vec!["--data-dir=.", "--mount=/local/:ir4_local:./",
                              "--mount=/local_1/:ir4_local:./a",
                              "--mount=/local_2/:ir4_local:./a/",
                              "--mount=/local_3/:ir4_local:a"];
        if std::path::MAIN_SEPARATOR == '\\'{
            params.push(r"--mount=/local_4/:ir4_local:.\a");
            params.push(r"--mount=/local_5/:ir4_local:.\a/");
            params.push(r"--mount=/local_6/:ir4_local:.\a\");
        }

        let last_mount = params.len() - 2;

        let (po, callback_result) = ServerInstance::run(&c, params , | server | {
            let bytes = fetch_bytes(&server.url_for("/local/eh.png?width=100")).unwrap();

            let info = fc::clients::stateless::LibClient {}.get_image_info(&bytes).expect("Image response should be valid");

            for ix in 1..last_mount + 1{

                let url = format!("/local_{ix}/eh2.png?w=1", ix=ix);
                println!("Testing {}", &url);
                let bytes = fetch_bytes(&server.url_for(&url)).unwrap();

                let info = fc::clients::stateless::LibClient {}.get_image_info(&bytes).expect("Image response should be valid");

                assert_eq!(server.get_status(&url)?, hyper::status::StatusCode::Ok);
            }

            assert_eq!(server.get_status("/local/notthere.jpg")?, hyper::status::StatusCode::NotFound);
            assert_eq!(server.get_status("/notrouted")?, hyper::status::StatusCode::NotFound);
            Ok(())
        });
        //po.expect_status_code(Some(0));

        callback_result.unwrap();
    }
}

trait ProcTestContextHttp{
 fn execute_callback<F,T>(&self, args_vec: Vec<&str>, valgrind_on_signal_death: bool, callback: F) -> (ProcOutput, T)
where F: Fn(&mut std::process::Child) -> T;

}
impl ProcTestContextHttp for ProcTestContext{

    ///
    /// Pass false for valgrind_on_signal_death if your callback might kill the child
    fn execute_callback<F,T>(&self, args_vec: Vec<&str>, valgrind_on_signal_death: bool, callback: F) -> (ProcOutput, T)
        where F: Fn(&mut std::process::Child) -> T {
        //TODO: serialize in a safer way - this isn't correct
        let full_invocation = format!("{} {}", &self.bin_location().to_str().unwrap(), args_vec.join(" "));

        let dir = self.working_dir();
        let exe = self.bin_location();

        let valgrind_copy_result = self.create_valgrind_suppressions();
        let _ = writeln!(&mut std::io::stderr(),
                         "Executing from folder {} with valgrind_suppressions {:?}\n{}",
                         dir.to_str().unwrap(),
                         valgrind_copy_result,
                         full_invocation);
        // change working dir to dir
        let mut cmd = Command::new(exe);
        cmd.args(args_vec.as_slice()).current_dir(dir).env("RUST_BACKTRACE", "1");

        //cmd.stderr(Stdio::piped()).stdout(Stdio::piped());
        cmd.stderr(Stdio::inherit()).stdout(Stdio::inherit());

        let mut child = cmd.spawn().expect("Failed to start?");

        let result = callback(&mut child);

        ///child.kill().unwrap();
        let timeout = Some(Duration::from_secs(1));

        let (status_code, output) = match timeout {
            Some(timeout) => {
                match child.wait_timeout(timeout).unwrap() {
                    Some(status) => (status.code(), None),
                    None => {
                        // child hasn't exited yet
                        child.kill().unwrap();
                        (child.wait().unwrap().code(), None)
                    }
                }
            }
            None => {
                let output: Output = child.wait_with_output().unwrap();
                (output.status.code(), Some(output))
            }
        };

        let _ = writeln!(&mut std::io::stderr(),
                         "exit code {:?}", status_code);

        // Double check we dumped output on segfault
        if status_code == None {
            if let Some(ref out) = output {
                std::io::stderr().write(&out.stderr).unwrap();
                std::io::stdout().write(&out.stdout).unwrap();
            }
            let _ = writeln!(&mut std::io::stderr(),
                             "exit code {:?}", status_code);
        }
        // Killed by signal.
        // 11 Segmentation fault
        // 4 illegal instruction 6 abort 8 floating point error
        if status_code == None && valgrind_on_signal_death {
            if std::env::var("VALGRIND_RUNNING").is_ok() {
                let _ = writeln!(&mut std::io::stderr(),
                                 "VALGRIND_RUNNING defined; skipping valgrind pass");
            } else {
                //ALLOW TO FAIL; valgrind may not be present
                let _ = writeln!(&mut std::io::stderr(),
                                 "Starting valgrind from within self-test:");
                let mut cmd = Command::new("valgrind");
                cmd.arg("-q").arg("--error-exitcode=9").arg(exe);
                cmd.args(args_vec.as_slice()).current_dir(dir).env("RUST_BACKTRACE", "1").env("VALGRIND_RUNNING", "1");

                let _ = writeln!(&mut std::io::stderr(),
                                 "{:?}", cmd);

                let _ = cmd.status(); //.expect("Failed to start valgrind?");
            }
        }

        match output {
            Some(out) => (ProcOutput::from(out), result),
            None => (ProcOutput::from_code(status_code), result)
        }
    }

}<|endoftext|>


<commit_before>// Thread parker implementation for Windows.
//
// This uses WaitOnAddress and WakeByAddressSingle if available (Windows 8+).
// This modern API is exactly the same as the futex syscalls the Linux thread
// parker uses. When These APIs are available, the implementation of this
// thread parker matches the Linux thread parker exactly.
//
// However, when the modern API is not available, this implementation falls
// back to NT Keyed Events, which are similar, but have some important
// differences. These are available since Windows XP.
//
// WaitOnAddress first checks the state of the thread parker to make sure it no
// WakeByAddressSingle calls can be missed between updating the parker state
// and calling the function.
//
// NtWaitForKeyedEvent does not have this option, and unconditionally blocks
// without checking the parker state first. Instead, NtReleaseKeyedEvent
// (unlike WakeByAddressSingle) *blocks* until it woke up a thread waiting for
// it by NtWaitForKeyedEvent. This way, we can be sure no events are missed,
// but we need to be careful not to block unpark() if park_timeout() was woken
// up by a timeout instead of unpark().
//
// Unlike WaitOnAddress, NtWaitForKeyedEvent/NtReleaseKeyedEvent operate on a
// HANDLE (created with NtCreateKeyedEvent). This means that we can be sure
// a succesfully awoken park() was awoken by unpark() and not a
// NtReleaseKeyedEvent call from some other code, as these events are not only
// matched by the key (address of the parker (state)), but also by this HANDLE.
// We lazily allocate this handle the first time it is needed.
//
// The fast path (calling park() after unpark() was already called) and the
// possible states are the same for both implementations. This is used here to
// make sure the fast path does not even check which API to use, but can return
// right away, independent of the used API. Only the slow paths (which will
// actually block/wake a thread) check which API is available and have
// different implementations.
//
// Unfortunately, NT Keyed Events are an undocumented Windows API. However:
// - This API is relatively simple with obvious behaviour, and there are
//   several (unofficial) articles documenting the details. [1]
// - `parking_lot` has been using this API for years (on Windows versions
//   before Windows 8). [2] Many big projects extensively use parking_lot,
//   such as servo and the Rust compiler itself.
// - It is the underlying API used by Windows SRW locks and Windows critical
//   sections. [3] [4]
// - The source code of the implementations of Wine, ReactOs, and Windows XP
//   are available and match the expected behaviour.
// - The main risk with an undocumented API is that it might change in the
//   future. But since we only use it for older versions of Windows, that's not
//   a problem.
// - Even if these functions do not block or wake as we expect (which is
//   unlikely, see all previous points), this implementation would still be
//   memory safe. The NT Keyed Events API is only used to sleep/block in the
//   right place.
//
// [1]: http://www.locklessinc.com/articles/keyed_events/
// [2]: https://github.com/Amanieu/parking_lot/commit/43abbc964e
// [3]: https://docs.microsoft.com/en-us/archive/msdn-magazine/2012/november/windows-with-c-the-evolution-of-synchronization-in-windows-and-c
// [4]: Windows Internals, Part 1, ISBN 9780735671300

use crate::convert::TryFrom;
use crate::ptr;
use crate::sync::atomic::{
    AtomicI8, AtomicUsize,
    Ordering::{Acquire, Relaxed, Release},
};
use crate::sys::{c, dur2timeout};
use crate::time::Duration;

pub struct Parker {
    state: AtomicI8,
}

const PARKED: i8 = -1;
const EMPTY: i8 = 0;
const NOTIFIED: i8 = 1;

// Notes about memory ordering:
//
// Memory ordering is only relevant for the relative ordering of operations
// between different variables. Even Ordering::Relaxed guarantees a
// monotonic/consistent order when looking at just a single atomic variable.
//
// So, since this parker is just a single atomic variable, we only need to look
// at the ordering guarantees we need to provide to the 'outside world'.
//
// The only memory ordering guarantee that parking and unparking provide, is
// that things which happened before unpark() are visible on the thread
// returning from park() afterwards. Otherwise, it was effectively unparked
// before unpark() was called while still consuming the 'token'.
//
// In other words, unpark() needs to synchronize with the part of park() that
// consumes the token and returns.
//
// This is done with a release-acquire synchronization, by using
// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using
// Ordering::Acquire when reading this state in park() after waking up.
impl Parker {
    pub fn new() -> Self {
        Self { state: AtomicI8::new(EMPTY) }
    }

    // Assumes this is only called by the thread that owns the Parker,
    // which means that `self.state != PARKED`.
    pub unsafe fn park(&self) {
        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
        // first case.
        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
            return;
        }

        if c::WaitOnAddress::is_available() {
            loop {
                // Wait for something to happen, assuming it's still set to PARKED.
                c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE);
                // Change NOTIFIED=>EMPTY but leave PARKED alone.
                if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED {
                    // Actually woken up by unpark().
                    return;
                } else {
                    // Spurious wake up. We loop to try again.
                }
            }
        } else {
            // Wait for unpark() to produce this event.
            c::NtWaitForKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
            // Set the state back to EMPTY (from either PARKED or NOTIFIED).
            // Note that we don't just write EMPTY, but use swap() to also
            // include an acquire-ordered read to synchronize with unpark()'s
            // release-ordered write.
            self.state.swap(EMPTY, Acquire);
        }
    }

    // Assumes this is only called by the thread that owns the Parker,
    // which means that `self.state != PARKED`.
    pub unsafe fn park_timeout(&self, timeout: Duration) {
        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
        // first case.
        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
            return;
        }

        if c::WaitOnAddress::is_available() {
            // Wait for something to happen, assuming it's still set to PARKED.
            c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, dur2timeout(timeout));
            // Set the state back to EMPTY (from either PARKED or NOTIFIED).
            // Note that we don't just write EMPTY, but use swap() to also
            // include an acquire-ordered read to synchronize with unpark()'s
            // release-ordered write.
            if self.state.swap(EMPTY, Acquire) == NOTIFIED {
                // Actually woken up by unpark().
            } else {
                // Timeout or spurious wake up.
                // We return either way, because we can't easily tell if it was the
                // timeout or not.
            }
        } else {
            // Need to wait for unpark() using NtWaitForKeyedEvent.
            let handle = keyed_event_handle();

            // NtWaitForKeyedEvent uses a unit of 100ns, and uses negative
            // values to indicate a relative time on the monotonic clock.
            // This is documented here for the underlying KeWaitForSingleObject function:
            // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-kewaitforsingleobject
            let mut timeout = match i64::try_from((timeout.as_nanos() + 99) / 100) {
                Ok(t) => -t,
                Err(_) => i64::MIN,
            };

            // Wait for unpark() to produce this event.
            let unparked = c::NtWaitForKeyedEvent(handle, self.ptr(), 0, &mut timeout) == c::STATUS_SUCCESS;

            // Set the state back to EMPTY (from either PARKED or NOTIFIED).
            let prev_state = self.state.swap(EMPTY, Acquire);

            if !unparked && prev_state == NOTIFIED {
                // We were awoken by a timeout, not by unpark(), but the state
                // was set to NOTIFIED, which means we *just* missed an
                // unpark(), which is now blocked on us to wait for it.
                // Wait for it to consume the event and unblock that thread.
                c::NtWaitForKeyedEvent(handle, self.ptr(), 0, ptr::null_mut());
            }
        }
    }

    pub fn unpark(&self) {
        // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
        // wake the thread in the first case.
        //
        // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
        // purpose, to make sure every unpark() has a release-acquire ordering
        // with park().
        if self.state.swap(NOTIFIED, Release) == PARKED {
            if c::WakeByAddressSingle::is_available() {
                unsafe {
                    c::WakeByAddressSingle(self.ptr());
                }
            } else {
                // If we run NtReleaseKeyedEvent before the waiting thread runs
                // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up.
                // If the waiting thread wakes up before we run NtReleaseKeyedEvent
                // (e.g. due to a timeout), this blocks until we do wake up a thread.
                // To prevent this thread from blocking indefinitely in that case,
                // park_impl() will, after seeing the state set to NOTIFIED after
                // waking up, call NtWaitForKeyedEvent again to unblock us.
                unsafe {
                    c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
                }
            }
        }
    }

    fn ptr(&self) -> c::LPVOID {
        &self.state as *const _ as c::LPVOID
    }
}

fn keyed_event_handle() -> c::HANDLE {
    const INVALID: usize = !0;
    static HANDLE: AtomicUsize = AtomicUsize::new(INVALID);
    match HANDLE.load(Relaxed) {
        INVALID => {
            let mut handle = c::INVALID_HANDLE_VALUE;
            unsafe {
                match c::NtCreateKeyedEvent(
                    &mut handle,
                    c::GENERIC_READ | c::GENERIC_WRITE,
                    ptr::null_mut(),
                    0,
                ) {
                    c::STATUS_SUCCESS => {}
                    r => panic!("Unable to create keyed event handle: error {}", r),
                }
            }
            match HANDLE.compare_exchange(INVALID, handle as usize, Relaxed, Relaxed) {
                Ok(_) => handle,
                Err(h) => {
                    // Lost the race to another thread initializing HANDLE before we did.
                    // Closing our handle and using theirs instead.
                    unsafe {
                        c::CloseHandle(handle);
                    }
                    h as c::HANDLE
                }
            }
        }
        handle => handle as c::HANDLE,
    }
}
<commit_msg>Formatting.<commit_after>// Thread parker implementation for Windows.
//
// This uses WaitOnAddress and WakeByAddressSingle if available (Windows 8+).
// This modern API is exactly the same as the futex syscalls the Linux thread
// parker uses. When These APIs are available, the implementation of this
// thread parker matches the Linux thread parker exactly.
//
// However, when the modern API is not available, this implementation falls
// back to NT Keyed Events, which are similar, but have some important
// differences. These are available since Windows XP.
//
// WaitOnAddress first checks the state of the thread parker to make sure it no
// WakeByAddressSingle calls can be missed between updating the parker state
// and calling the function.
//
// NtWaitForKeyedEvent does not have this option, and unconditionally blocks
// without checking the parker state first. Instead, NtReleaseKeyedEvent
// (unlike WakeByAddressSingle) *blocks* until it woke up a thread waiting for
// it by NtWaitForKeyedEvent. This way, we can be sure no events are missed,
// but we need to be careful not to block unpark() if park_timeout() was woken
// up by a timeout instead of unpark().
//
// Unlike WaitOnAddress, NtWaitForKeyedEvent/NtReleaseKeyedEvent operate on a
// HANDLE (created with NtCreateKeyedEvent). This means that we can be sure
// a succesfully awoken park() was awoken by unpark() and not a
// NtReleaseKeyedEvent call from some other code, as these events are not only
// matched by the key (address of the parker (state)), but also by this HANDLE.
// We lazily allocate this handle the first time it is needed.
//
// The fast path (calling park() after unpark() was already called) and the
// possible states are the same for both implementations. This is used here to
// make sure the fast path does not even check which API to use, but can return
// right away, independent of the used API. Only the slow paths (which will
// actually block/wake a thread) check which API is available and have
// different implementations.
//
// Unfortunately, NT Keyed Events are an undocumented Windows API. However:
// - This API is relatively simple with obvious behaviour, and there are
//   several (unofficial) articles documenting the details. [1]
// - `parking_lot` has been using this API for years (on Windows versions
//   before Windows 8). [2] Many big projects extensively use parking_lot,
//   such as servo and the Rust compiler itself.
// - It is the underlying API used by Windows SRW locks and Windows critical
//   sections. [3] [4]
// - The source code of the implementations of Wine, ReactOs, and Windows XP
//   are available and match the expected behaviour.
// - The main risk with an undocumented API is that it might change in the
//   future. But since we only use it for older versions of Windows, that's not
//   a problem.
// - Even if these functions do not block or wake as we expect (which is
//   unlikely, see all previous points), this implementation would still be
//   memory safe. The NT Keyed Events API is only used to sleep/block in the
//   right place.
//
// [1]: http://www.locklessinc.com/articles/keyed_events/
// [2]: https://github.com/Amanieu/parking_lot/commit/43abbc964e
// [3]: https://docs.microsoft.com/en-us/archive/msdn-magazine/2012/november/windows-with-c-the-evolution-of-synchronization-in-windows-and-c
// [4]: Windows Internals, Part 1, ISBN 9780735671300

use crate::convert::TryFrom;
use crate::ptr;
use crate::sync::atomic::{
    AtomicI8, AtomicUsize,
    Ordering::{Acquire, Relaxed, Release},
};
use crate::sys::{c, dur2timeout};
use crate::time::Duration;

pub struct Parker {
    state: AtomicI8,
}

const PARKED: i8 = -1;
const EMPTY: i8 = 0;
const NOTIFIED: i8 = 1;

// Notes about memory ordering:
//
// Memory ordering is only relevant for the relative ordering of operations
// between different variables. Even Ordering::Relaxed guarantees a
// monotonic/consistent order when looking at just a single atomic variable.
//
// So, since this parker is just a single atomic variable, we only need to look
// at the ordering guarantees we need to provide to the 'outside world'.
//
// The only memory ordering guarantee that parking and unparking provide, is
// that things which happened before unpark() are visible on the thread
// returning from park() afterwards. Otherwise, it was effectively unparked
// before unpark() was called while still consuming the 'token'.
//
// In other words, unpark() needs to synchronize with the part of park() that
// consumes the token and returns.
//
// This is done with a release-acquire synchronization, by using
// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using
// Ordering::Acquire when reading this state in park() after waking up.
impl Parker {
    pub fn new() -> Self {
        Self { state: AtomicI8::new(EMPTY) }
    }

    // Assumes this is only called by the thread that owns the Parker,
    // which means that `self.state != PARKED`.
    pub unsafe fn park(&self) {
        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
        // first case.
        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
            return;
        }

        if c::WaitOnAddress::is_available() {
            loop {
                // Wait for something to happen, assuming it's still set to PARKED.
                c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE);
                // Change NOTIFIED=>EMPTY but leave PARKED alone.
                if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED {
                    // Actually woken up by unpark().
                    return;
                } else {
                    // Spurious wake up. We loop to try again.
                }
            }
        } else {
            // Wait for unpark() to produce this event.
            c::NtWaitForKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
            // Set the state back to EMPTY (from either PARKED or NOTIFIED).
            // Note that we don't just write EMPTY, but use swap() to also
            // include an acquire-ordered read to synchronize with unpark()'s
            // release-ordered write.
            self.state.swap(EMPTY, Acquire);
        }
    }

    // Assumes this is only called by the thread that owns the Parker,
    // which means that `self.state != PARKED`.
    pub unsafe fn park_timeout(&self, timeout: Duration) {
        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
        // first case.
        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
            return;
        }

        if c::WaitOnAddress::is_available() {
            // Wait for something to happen, assuming it's still set to PARKED.
            c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, dur2timeout(timeout));
            // Set the state back to EMPTY (from either PARKED or NOTIFIED).
            // Note that we don't just write EMPTY, but use swap() to also
            // include an acquire-ordered read to synchronize with unpark()'s
            // release-ordered write.
            if self.state.swap(EMPTY, Acquire) == NOTIFIED {
                // Actually woken up by unpark().
            } else {
                // Timeout or spurious wake up.
                // We return either way, because we can't easily tell if it was the
                // timeout or not.
            }
        } else {
            // Need to wait for unpark() using NtWaitForKeyedEvent.
            let handle = keyed_event_handle();

            // NtWaitForKeyedEvent uses a unit of 100ns, and uses negative
            // values to indicate a relative time on the monotonic clock.
            // This is documented here for the underlying KeWaitForSingleObject function:
            // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-kewaitforsingleobject
            let mut timeout = match i64::try_from((timeout.as_nanos() + 99) / 100) {
                Ok(t) => -t,
                Err(_) => i64::MIN,
            };

            // Wait for unpark() to produce this event.
            let unparked =
                c::NtWaitForKeyedEvent(handle, self.ptr(), 0, &mut timeout) == c::STATUS_SUCCESS;

            // Set the state back to EMPTY (from either PARKED or NOTIFIED).
            let prev_state = self.state.swap(EMPTY, Acquire);

            if !unparked && prev_state == NOTIFIED {
                // We were awoken by a timeout, not by unpark(), but the state
                // was set to NOTIFIED, which means we *just* missed an
                // unpark(), which is now blocked on us to wait for it.
                // Wait for it to consume the event and unblock that thread.
                c::NtWaitForKeyedEvent(handle, self.ptr(), 0, ptr::null_mut());
            }
        }
    }

    pub fn unpark(&self) {
        // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
        // wake the thread in the first case.
        //
        // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
        // purpose, to make sure every unpark() has a release-acquire ordering
        // with park().
        if self.state.swap(NOTIFIED, Release) == PARKED {
            if c::WakeByAddressSingle::is_available() {
                unsafe {
                    c::WakeByAddressSingle(self.ptr());
                }
            } else {
                // If we run NtReleaseKeyedEvent before the waiting thread runs
                // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up.
                // If the waiting thread wakes up before we run NtReleaseKeyedEvent
                // (e.g. due to a timeout), this blocks until we do wake up a thread.
                // To prevent this thread from blocking indefinitely in that case,
                // park_impl() will, after seeing the state set to NOTIFIED after
                // waking up, call NtWaitForKeyedEvent again to unblock us.
                unsafe {
                    c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
                }
            }
        }
    }

    fn ptr(&self) -> c::LPVOID {
        &self.state as *const _ as c::LPVOID
    }
}

fn keyed_event_handle() -> c::HANDLE {
    const INVALID: usize = !0;
    static HANDLE: AtomicUsize = AtomicUsize::new(INVALID);
    match HANDLE.load(Relaxed) {
        INVALID => {
            let mut handle = c::INVALID_HANDLE_VALUE;
            unsafe {
                match c::NtCreateKeyedEvent(
                    &mut handle,
                    c::GENERIC_READ | c::GENERIC_WRITE,
                    ptr::null_mut(),
                    0,
                ) {
                    c::STATUS_SUCCESS => {}
                    r => panic!("Unable to create keyed event handle: error {}", r),
                }
            }
            match HANDLE.compare_exchange(INVALID, handle as usize, Relaxed, Relaxed) {
                Ok(_) => handle,
                Err(h) => {
                    // Lost the race to another thread initializing HANDLE before we did.
                    // Closing our handle and using theirs instead.
                    unsafe {
                        c::CloseHandle(handle);
                    }
                    h as c::HANDLE
                }
            }
        }
        handle => handle as c::HANDLE,
    }
}
<|endoftext|>


<commit_before><commit_msg>Use nicer idiom to iterate the rectangle<commit_after><|endoftext|>


<commit_before>use ndarray::{Array3, ArrayView3, Zip};
use ndarray_parallel::prelude::*;
use slog::Logger;
use potential;
use config;
use config::*;

#[derive(Debug)]
pub struct Potentials {
    pub v: Array3<f64>,
    a: Array3<f64>,
    b: Array3<f64>,
    epsilon: f64,
}

/// Parameters generated by the initialisation routine, potentials and wavefunction (phi).
#[derive(Debug)]
struct Params<'a> {
    potentials: Potentials,
    phi: &'a mut Array3<f64>,
}

#[derive(Debug)]
struct Observables {
    energy: f64,
    norm2: f64,
    v_infinity: f64,
    r2: f64,
}

fn load_potential_arrays(config: &Config) -> Potentials {
    let mut minima: f64 = 1e20;

    let result = match config.potential {
        PotentialType::FromFile => potential::from_file(),
        PotentialType::FromScript => potential::from_script(),
        _ => potential::generate(config),
    };
    let v: Array3<f64> = match result {
        Ok(r) => r,
        Err(err) => panic!("Error: {}", err),
    };

    let b = 1. / (1. + config.grid.dt * &v / 2.);
    let a = (1. - config.grid.dt * &v / 2.) * &b;

    // We can't do this in a par.
    // AFAIK, this is the safest way to work with the float here.
    for el in v.iter() {
        if el.is_finite() {
            minima = minima.min(*el);
        }
    }
    //Get 2*abs(min(potential)) for offset of beta
    let epsilon = 2. * minima.abs();

    Potentials {
        v: v,
        a: a,
        b: b,
        epsilon: epsilon,
    }
}

/// Runs the actual computation once system is setup and ready.
pub fn solve(config: &Config, log: &Logger) {

    info!(log, "Loading potential arrays");
    let params = Params {
        potentials: load_potential_arrays(config),
        phi: &mut set_initial_conditions(config),
    };
    info!(log, "Setting initial conditions for wavefunction");
    if config.output.save_potential {
        //TODO: Build output routine.
        //Not sure if we should use someting like messagepack as there are matlab
        //and python bindings, or try for hdf5. The rust bindings there are pretty
        //shonky. So not sure. We'll need a text only option anyhow, so build that fist.
    }

    if config.wavenum > 0 {
        //TODO: We restart from an output file.
    }

    //let params = Params::initialise(config, log);
    let step = 0;
    //    let mut done = false;
    // while !done {
    //     //syncboundaries <- not needed until MPI
    info!(log, "Computing observables");
    let observables = compute_observables(config, &params);
    println!("{:?}", observables);
    if step % config.output.snap_update == 0 {
        //TODO: I think we can do away with SNAPUPDATE now. Kill this if.
        info!(log, "snapupdate: symmetrise");
        config::symmetrise_wavefunction(config, params.phi);
        normalise_wavefunction(params.phi, observables.norm2);
    }
    //     //orthognalise_wavefunction (if wavenum>0)
    //     //output_measurements
    //     if step < config.max_steps {
    //         evolve(config.output.screen_update, &params.phi);
    //     }
    //     step += config.output.screen_update;
    //     done = step <= config.max_steps;
    // }

}

/// Computes observable values of the system, for example the energy
fn compute_observables(config: &Config, params: &Params) -> Observables {
    let energy = wfnc_energy(config, params);
    let dims = params.phi.dim();
    let work = params.phi
        .slice(s![3..(dims.0 as isize) - 3, 3..(dims.1 as isize) - 3, 3..(dims.2 as isize) - 3]);

    let norm2 = get_norm_squared(&work);
    let v_infinity = get_v_infinity_expectation_value(&work, config);
    let r2 = get_r_squared_expectation_value(&work, &config.grid);

    Observables {
        energy: energy,
        norm2: norm2,
        v_infinity: v_infinity,
        r2: r2,
    }
}

/// Normalisation of wavefunction
fn get_norm_squared(w: &ArrayView3<f64>) -> f64 {
    //NOTE: No complex conjugation due to all real input for now
    (w * w).scalar_sum()
}

/// Get v infinity
fn get_v_infinity_expectation_value(w: &ArrayView3<f64>, config: &Config) -> f64 {
    //NOTE: No complex conjugation due to all real input for now
    let mut work = Array3::<f64>::zeros(w.dim());
    Zip::indexed(&mut work)
        .and(w)
        .par_apply(|(i, j, k), work, &w| {
            let idx = Index3 { x: i, y: j, z: k };
            let potsub = match potential::potential_sub(config, &idx) {
                Ok(p) => p,
                Err(err) => panic!("Error: {}", err),
            };
            *work = w * w * potsub;
        });
    work.scalar_sum()
}

/// Get r2
fn get_r_squared_expectation_value(w: &ArrayView3<f64>, grid: &Grid) -> f64 {
    //NOTE: No complex conjugation due to all real input for now
    let mut work = Array3::<f64>::zeros(w.dim());
    Zip::indexed(&mut work)
        .and(w)
        .par_apply(|(i, j, k), work, &w| {
            let idx = Index3 { x: i, y: j, z: k };
            let r = potential::calculate_r(&idx, grid);
            *work = w * w * r;
        });
    work.scalar_sum()
}

/// Gets energy of the corresponding wavefunction
//TODO: We can probably drop the config requirement and replace it with a grid modifier of dn*mass
fn wfnc_energy(config: &Config, params: &Params) -> f64 {
    let num = &config.grid.size; //NOTE: We could also obtain this by phi.dim() if other config values are not needed.

    let w = params.phi
        .slice(s![3..3 + num.x as isize, 3..3 + num.y as isize, 3..3 + num.z as isize]);
    let v = params.potentials
        .v
        .slice(s![3..3 + num.x as isize, 3..3 + num.y as isize, 3..3 + num.z as isize]);

    let mut work = Array3::<f64>::zeros(w.dim());
    //NOTE: TODO: We don't have any complex conjugation here.
    // Complete matrix multiplication step using 7 point central differenc
    // TODO: Option for 3 or 5 point caclulation
    Zip::indexed(&mut work)
        .and(v)
        .and(w)
        .par_apply(|(i, j, k), work, &v, &w| {
            // Offset indexes as we are already in a slice
            let lx = i as isize + 3;
            let ly = j as isize + 3;
            let lz = k as isize + 3;
            let o = 3;
            // get a slice which gives us our matrix of central difference points
            let l = params.phi
                .slice(s![lx - 3..lx + 4, ly - 3..ly + 4, lz - 3..lz + 4]);
            // l can now be indexed with local offset `o` and modifiers
            *work = v * w * w -
                    w *
                    (2. * l[[o + 3, o, o]] - 27. * l[[o + 2, o, o]] + 270. * l[[o + 1, o, o]] +
                     270. * l[[o - 1, o, o]] -
                     27. * l[[o - 2, o, o]] + 2. * l[[o - 3, o, o]] +
                     2. * l[[o, o + 3, o]] - 27. * l[[o, o + 2, o]] +
                     270. * l[[o, o + 1, o]] +
                     270. * l[[o, o - 1, o]] -
                     27. * l[[o, o - 2, o]] + 2. * l[[o, o - 3, o]] +
                     2. * l[[o, o, o + 3]] - 27. * l[[o, o, o + 2]] +
                     270. * l[[o, o, o + 1]] +
                     270. * l[[o, o, o - 1]] -
                     27. * l[[o, o, o - 2]] + 2. * l[[o, o, o - 3]] -
                     1470. * w) / (360. * config.grid.dn.powi(2) * config.mass);
        });
    // Sum result for total energy.
    work.scalar_sum()
}

fn normalise_wavefunction(w: &mut Array3<f64>, norm2: f64) {
    //TODO: This can be moved directly into the calculation for now. It's only here due to normalisationCollect
    let norm = norm2.sqrt();
    w.par_map_inplace(|el| *el /= norm);
}
/// Evolves the solution a number of `steps`
fn evolve(steps: f64, w: &Array3<f64>) {}
<commit_msg>Evolve is implemented, but probably not working at all..<commit_after>use ndarray::{Array3, ArrayView3, Zip};
use ndarray_parallel::prelude::*;
use slog::Logger;
use potential;
use config;
use config::*;

#[derive(Debug)]
pub struct Potentials {
    pub v: Array3<f64>,
    a: Array3<f64>,
    b: Array3<f64>,
    epsilon: f64,
}

/// Parameters generated by the initialisation routine, potentials and wavefunction (phi).
#[derive(Debug)]
struct Params<'a> {
    potentials: Potentials,
    phi: &'a mut Array3<f64>,
}

#[derive(Debug)]
struct Observables {
    energy: f64,
    norm2: f64,
    v_infinity: f64,
    r2: f64,
}

fn load_potential_arrays(config: &Config) -> Potentials {
    let mut minima: f64 = 1e20;

    let result = match config.potential {
        PotentialType::FromFile => potential::from_file(),
        PotentialType::FromScript => potential::from_script(),
        _ => potential::generate(config),
    };
    let v: Array3<f64> = match result {
        Ok(r) => r,
        Err(err) => panic!("Error: {}", err),
    };

    let b = 1. / (1. + config.grid.dt * &v / 2.);
    let a = (1. - config.grid.dt * &v / 2.) * &b;

    // We can't do this in a par.
    // AFAIK, this is the safest way to work with the float here.
    for el in v.iter() {
        if el.is_finite() {
            minima = minima.min(*el);
        }
    }
    //Get 2*abs(min(potential)) for offset of beta
    let epsilon = 2. * minima.abs();

    Potentials {
        v: v,
        a: a,
        b: b,
        epsilon: epsilon,
    }
}

/// Runs the actual computation once system is setup and ready.
pub fn solve(config: &Config, log: &Logger) {

    info!(log, "Loading potential arrays");
    let mut params = Params {
        potentials: load_potential_arrays(config),
        phi: &mut set_initial_conditions(config),
    };
    info!(log, "Setting initial conditions for wavefunction");
    if config.output.save_potential {
        //TODO: Build output routine.
        //Not sure if we should use someting like messagepack as there are matlab
        //and python bindings, or try for hdf5. The rust bindings there are pretty
        //shonky. So not sure. We'll need a text only option anyhow, so build that fist.
    }

    if config.wavenum > 0 {
        //TODO: We restart from an output file.
    }

    //let params = Params::initialise(config, log);
    let mut step = 0.;
    //    let mut done = false;
    // while !done {
    //     //syncboundaries <- not needed until MPI
    info!(log, "Computing observables");
    let observables = compute_observables(config, &params);
    println!("{:?}", observables);
    //TODO: Need to do a floating point comparison here if we want steps to be more than 2^64 (~1e19)
    //if step % config.output.snap_update == 0 {
    //TODO: I think we can do away with SNAPUPDATE now. Kill this if.
    info!(log, "snapupdate: symmetrise");
    config::symmetrise_wavefunction(config, params.phi);
    normalise_wavefunction(params.phi, observables.norm2);
    //}
    //     //orthognalise_wavefunction (if wavenum>0)
    //     //output_measurements
    if step < config.max_steps {
        info!(log, "Evolving {} steps", config.output.screen_update);
        evolve(config, &mut params);
    }
    step += config.output.screen_update;
    let observables2 = compute_observables(config, &params);
    println!("{:?}", observables2);
    //     done = step <= config.max_steps;
    // }

}

/// Computes observable values of the system, for example the energy
fn compute_observables(config: &Config, params: &Params) -> Observables {
    let energy = wfnc_energy(config, params);
    let dims = params.phi.dim();
    let work = params.phi
        .slice(s![3..(dims.0 as isize) - 3, 3..(dims.1 as isize) - 3, 3..(dims.2 as isize) - 3]);

    let norm2 = get_norm_squared(&work);
    let v_infinity = get_v_infinity_expectation_value(&work, config);
    let r2 = get_r_squared_expectation_value(&work, &config.grid);

    Observables {
        energy: energy,
        norm2: norm2,
        v_infinity: v_infinity,
        r2: r2,
    }
}

/// Normalisation of wavefunction
fn get_norm_squared(w: &ArrayView3<f64>) -> f64 {
    //NOTE: No complex conjugation due to all real input for now
    (w * w).scalar_sum()
}

/// Get v infinity
fn get_v_infinity_expectation_value(w: &ArrayView3<f64>, config: &Config) -> f64 {
    //NOTE: No complex conjugation due to all real input for now
    let mut work = Array3::<f64>::zeros(w.dim());
    Zip::indexed(&mut work)
        .and(w)
        .par_apply(|(i, j, k), work, &w| {
            let idx = Index3 { x: i, y: j, z: k };
            let potsub = match potential::potential_sub(config, &idx) {
                Ok(p) => p,
                Err(err) => panic!("Error: {}", err),
            };
            *work = w * w * potsub;
        });
    work.scalar_sum()
}

/// Get r2
fn get_r_squared_expectation_value(w: &ArrayView3<f64>, grid: &Grid) -> f64 {
    //NOTE: No complex conjugation due to all real input for now
    let mut work = Array3::<f64>::zeros(w.dim());
    Zip::indexed(&mut work)
        .and(w)
        .par_apply(|(i, j, k), work, &w| {
            let idx = Index3 { x: i, y: j, z: k };
            let r = potential::calculate_r(&idx, grid);
            *work = w * w * r;
        });
    work.scalar_sum()
}

/// Gets energy of the corresponding wavefunction
//TODO: We can probably drop the config requirement and replace it with a grid modifier of dn*mass
fn wfnc_energy(config: &Config, params: &Params) -> f64 {
    let num = &config.grid.size; //NOTE: We could also obtain this by phi.dim() if other config values are not needed.

    let w = params.phi
        .slice(s![3..3 + num.x as isize, 3..3 + num.y as isize, 3..3 + num.z as isize]);
    let v = params.potentials
        .v
        .slice(s![3..3 + num.x as isize, 3..3 + num.y as isize, 3..3 + num.z as isize]);

    let mut work = Array3::<f64>::zeros(w.dim());
    //NOTE: TODO: We don't have any complex conjugation here.
    // Complete matrix multiplication step using 7 point central differenc
    // TODO: Option for 3 or 5 point caclulation
    Zip::indexed(&mut work)
        .and(v)
        .and(w)
        .par_apply(|(i, j, k), work, &v, &w| {
            // Offset indexes as we are already in a slice
            let lx = i as isize + 3;
            let ly = j as isize + 3;
            let lz = k as isize + 3;
            let o = 3;
            // get a slice which gives us our matrix of central difference points
            let l = params.phi
                .slice(s![lx - 3..lx + 4, ly - 3..ly + 4, lz - 3..lz + 4]);
            // l can now be indexed with local offset `o` and modifiers
            *work = v * w * w -
                    w *
                    (2. * l[[o + 3, o, o]] - 27. * l[[o + 2, o, o]] + 270. * l[[o + 1, o, o]] +
                     270. * l[[o - 1, o, o]] -
                     27. * l[[o - 2, o, o]] + 2. * l[[o - 3, o, o]] +
                     2. * l[[o, o + 3, o]] - 27. * l[[o, o + 2, o]] +
                     270. * l[[o, o + 1, o]] +
                     270. * l[[o, o - 1, o]] -
                     27. * l[[o, o - 2, o]] + 2. * l[[o, o - 3, o]] +
                     2. * l[[o, o, o + 3]] - 27. * l[[o, o, o + 2]] +
                     270. * l[[o, o, o + 1]] +
                     270. * l[[o, o, o - 1]] -
                     27. * l[[o, o, o - 2]] + 2. * l[[o, o, o - 3]] -
                     1470. * w) / (360. * config.grid.dn.powi(2) * config.mass);
        });
    // Sum result for total energy.
    work.scalar_sum()
}

/// Normalisation of the wavefunction
fn normalise_wavefunction(w: &mut Array3<f64>, norm2: f64) {
    //TODO: This can be moved directly into the calculation for now. It's only here due to normalisationCollect
    let norm = norm2.sqrt();
    w.par_map_inplace(|el| *el /= norm);
}

/// Evolves the solution a number of `steps`
fn evolve(config: &Config, params: &mut Params) {
    //without mpi, this is just update interior (which is really updaterule if we dont need W)

    let dims = params.phi.dim();
    let mut work_dims = params.phi.dim();
    work_dims.0 -= 6;
    work_dims.1 -= 6;
    work_dims.2 -= 6;
    let mut work = Array3::<f64>::zeros(work_dims);
    //Scope so we can drop the borrow on params.phi
    {
        let steps = config.output.screen_update;
        let w = params.phi
            .slice(s![3..(dims.0 as isize) - 3,
                      3..(dims.1 as isize) - 3,
                      3..(dims.2 as isize) - 3]);
        let a = params.potentials
            .a
            .slice(s![3..(dims.0 as isize) - 3,
                      3..(dims.1 as isize) - 3,
                      3..(dims.2 as isize) - 3]);
        let b = params.potentials
            .b
            .slice(s![3..(dims.0 as isize) - 3,
                      3..(dims.1 as isize) - 3,
                      3..(dims.2 as isize) - 3]);

        //NOTE: TODO: We don't have any complex conjugation here.
        // Complete matrix multiplication step using 7 point central differenc
        // TODO: Option for 3 or 5 point caclulation
        Zip::indexed(&mut work)
            .and(w)
            .and(a)
            .and(b)
            .par_apply(|(i, j, k), work, &w, &a, &b| {
                // Offset indexes as we are already in a slice
                let lx = i as isize + 3;
                let ly = j as isize + 3;
                let lz = k as isize + 3;
                let o = 3;
                // get a slice which gives us our matrix of central difference points
                let l = params.phi
                    .slice(s![lx - 3..lx + 4, ly - 3..ly + 4, lz - 3..lz + 4]);
                // l can now be indexed with local offset `o` and modifiers
                *work = w * a +
                        b * steps *
                        (2. * l[[o + 3, o, o]] - 27. * l[[o + 2, o, o]] + 270. * l[[o + 1, o, o]] +
                         270. * l[[o - 1, o, o]] - 27. * l[[o - 2, o, o]] +
                         2. * l[[o - 3, o, o]] + 2. * l[[o, o + 3, o]] -
                         27. * l[[o, o + 2, o]] + 270. * l[[o, o + 1, o]] +
                         270. * l[[o, o - 1, o]] - 27. * l[[o, o - 2, o]] +
                         2. * l[[o, o - 3, o]] + 2. * l[[o, o, o + 3]] -
                         27. * l[[o, o, o + 2]] + 270. * l[[o, o, o + 1]] +
                         270. * l[[o, o, o - 1]] - 27. * l[[o, o, o - 2]] +
                         2. * l[[o, o, o - 3]] - 1470. * w) /
                        (360. * config.grid.dn.powi(2) * config.mass);
            });
    }
    let mut w_fill = params.phi
        .slice_mut(s![3..(dims.0 as isize) - 3,
                      3..(dims.1 as isize) - 3,
                      3..(dims.2 as isize) - 3]);
    for ((i, j, k), el) in w_fill.indexed_iter_mut() {
        *el = work[[i, j, k]];
    }
}
<|endoftext|>