<commit_before>use std::sync::{Arc, Weak};
use std::collections::HashMap;
use builder::module;
use elements::{Module, ExportEntry, Internal, GlobalEntry, GlobalType,
	ValueType, InitExpr, Opcode, Opcodes};
use interpreter::Error;
use interpreter::env_native::NATIVE_INDEX_FUNC_MIN;
use interpreter::module::{ModuleInstanceInterface, ModuleInstance, ExecutionParams,
	ItemIndex, CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature};
use interpreter::memory::{MemoryInstance, LINEAR_MEMORY_PAGE_SIZE};
use interpreter::table::TableInstance;
use interpreter::value::RuntimeValue;
use interpreter::variable::{VariableInstance, VariableType};

/// Memory address, at which stack begins.
const DEFAULT_STACK_BASE: u32 = 0;
/// Memory, allocated for stack.
const DEFAULT_TOTAL_STACK: u32 = 5 * 1024 * 1024;
/// Total memory, allocated by default.
const DEFAULT_TOTAL_MEMORY: u32 = 16 * 1024 * 1024;
/// Whether memory can be enlarged, or not.
const DEFAULT_ALLOW_MEMORY_GROWTH: bool = false;
/// Default tableBase variable value.
const DEFAULT_TABLE_BASE: u32 = 0;

/// Defaul table size.
const DEFAULT_TABLE_SIZE: u32 = 16;

/// Index of default memory.
const INDEX_MEMORY: u32 = 0;

/// Index of default table.
const INDEX_TABLE: u32 = 0;

/// Index of STACK_BASE global variable.
const INDEX_GLOBAL_STACK_BASE: u32 = 0;
/// Index of STACK_TOP global variable.
const INDEX_GLOBAL_STACK_TOP: u32 = 1;
/// Index of STACK_MAX global variable.
const INDEX_GLOBAL_STACK_MAX: u32 = 2;
/// Index of DYNAMIC_BASE global variable.
const INDEX_GLOBAL_DYNAMIC_BASE: u32 = 3;
/// Index of DYNAMICTOP_PTR global variable.
const INDEX_GLOBAL_DYNAMICTOP_PTR: u32 = 4;
/// Index of TOTAL_MEMORY global variable.
const INDEX_GLOBAL_TOTAL_MEMORY: u32 = 5;
/// Index of ABORT global variable.
const INDEX_GLOBAL_ABORT: u32 = 6;
/// Index of EXITSTATUS global variable.
const INDEX_GLOBAL_EXIT_STATUS: u32 = 7;
/// Index of tableBase global variable.
const INDEX_GLOBAL_TABLE_BASE: u32 = 8;

/// Index of abort function.
const INDEX_FUNC_ABORT: u32 = 0;
/// Index of assert function.
const INDEX_FUNC_ASSERT: u32 = 1;
/// Index of enlargeMemory function.
const INDEX_FUNC_ENLARGE_MEMORY: u32 = 2;
/// Index of getTotalMemory function.
const INDEX_FUNC_GET_TOTAL_MEMORY: u32 = 3;
/// Min index of reserver function.
const INDEX_FUNC_MIN_NONUSED: u32 = 4;
/// Max index of reserved function.
const INDEX_FUNC_MAX: u32 = NATIVE_INDEX_FUNC_MIN - 1;

/// Environment parameters.
pub struct EnvParams {
	/// Stack size in bytes.
	pub total_stack: u32,
	/// Total memory size in bytes.
	pub total_memory: u32,
	/// Allow memory growth.
	pub allow_memory_growth: bool,
}

pub struct EnvModuleInstance {
	_params: EnvParams,
	instance: ModuleInstance,
}

impl EnvModuleInstance {
	pub fn new(params: EnvParams, module: Module) -> Result<Self, Error> {
		let instance = ModuleInstance::new(Weak::default(), "env".into(), module)?;

		Ok(EnvModuleInstance {
			_params: params,
			instance: instance,
		})
	}
}

impl ModuleInstanceInterface for EnvModuleInstance {
	fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
		self.instance.execute_index(index, params)
	}

	fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
		self.instance.execute_export(name, params)
	}

	fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result<Internal, Error> {
		self.instance.export_entry(name, required_type)
	}

	fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
		self.instance.table(index)
	}

	fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error> {
		self.instance.memory(index)
	}

	fn global(&self, index: ItemIndex, variable_type: Option<VariableType>) -> Result<Arc<VariableInstance>, Error> {
		self.instance.global(index, variable_type)
	}

	fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, Error> {
		self.instance.function_type(function_index)
	}

	fn function_type_by_index(&self, type_index: u32) -> Result<FunctionSignature, Error> {
		self.instance.function_type_by_index(type_index)
	}

	fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> {
		self.instance.function_reference(index, externals)
	}

	fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> {
		self.instance.function_reference_indirect(table_idx, type_idx, func_idx, externals)
	}

	fn function_body<'a>(&'a self, _internal_index: u32) -> Result<Option<InternalFunction<'a>>, Error> {
		Ok(None)
	}

	fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result<Option<RuntimeValue>, Error> {
		// to make interpreter independent of *SCRIPTEN runtime, just make abort/assert = interpreter Error
		match index {
			INDEX_FUNC_ABORT => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_ABORT), Some(VariableType::I32))
				.and_then(|g| g.set(RuntimeValue::I32(1)))
				.and_then(|_| Err(Error::Trap("abort".into()))),
			INDEX_FUNC_ASSERT => outer.value_stack.pop_as::<i32>()
				.and_then(|condition| if condition == 0 {
					self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_ABORT), Some(VariableType::I32))
						.and_then(|g| g.set(RuntimeValue::I32(1)))
						.and_then(|_| Err(Error::Trap("assertion failed".into())))
				} else {
					Ok(None)
				}),
			INDEX_FUNC_ENLARGE_MEMORY => Ok(Some(RuntimeValue::I32(0))), // TODO: support memory enlarge
			INDEX_FUNC_GET_TOTAL_MEMORY => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_TOTAL_MEMORY), Some(VariableType::I32))
				.map(|g| g.get())
				.map(Some),
			INDEX_FUNC_MIN_NONUSED ... INDEX_FUNC_MAX => Err(Error::Trap("unimplemented".into())),
			_ => Err(Error::Trap(format!("trying to call function with index {} in env module", index))),
		}
	}
}

pub fn env_module(params: EnvParams) -> Result<EnvModuleInstance, Error> {
	debug_assert!(params.total_stack < params.total_memory);
	debug_assert!((params.total_stack % LINEAR_MEMORY_PAGE_SIZE) == 0);
	debug_assert!((params.total_memory % LINEAR_MEMORY_PAGE_SIZE) == 0);
	let builder = module()
		// memory regions
		.memory()
			.with_min(params.total_memory / LINEAR_MEMORY_PAGE_SIZE)
			.with_max(params.max_memory().map(|m| m / LINEAR_MEMORY_PAGE_SIZE))
			.build()
			.with_export(ExportEntry::new("memory".into(), Internal::Memory(INDEX_MEMORY)))
		// tables
		.table()
			.with_min(DEFAULT_TABLE_SIZE)
			.build()
			.with_export(ExportEntry::new("table".into(), Internal::Table(INDEX_TABLE)))
		// globals
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(DEFAULT_STACK_BASE as i32)])))
			.with_export(ExportEntry::new("STACK_BASE".into(), Internal::Global(INDEX_GLOBAL_STACK_BASE)))
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const(DEFAULT_STACK_BASE as i32)])))
			.with_export(ExportEntry::new("STACKTOP".into(), Internal::Global(INDEX_GLOBAL_STACK_TOP)))
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const((DEFAULT_STACK_BASE + params.total_stack) as i32)])))
			.with_export(ExportEntry::new("STACK_MAX".into(), Internal::Global(INDEX_GLOBAL_STACK_MAX)))
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const((DEFAULT_STACK_BASE + params.total_stack) as i32)])))
			.with_export(ExportEntry::new("DYNAMIC_BASE".into(), Internal::Global(INDEX_GLOBAL_DYNAMIC_BASE)))
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const((DEFAULT_STACK_BASE + params.total_stack) as i32)])))
			.with_export(ExportEntry::new("DYNAMICTOP_PTR".into(), Internal::Global(INDEX_GLOBAL_DYNAMICTOP_PTR)))
			.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, params.allow_memory_growth), InitExpr::new(vec![Opcode::I32Const(params.total_memory as i32)])))
			.with_export(ExportEntry::new("TOTAL_MEMORY".into(), Internal::Global(INDEX_GLOBAL_TOTAL_MEMORY)))
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const(0)])))
			.with_export(ExportEntry::new("ABORT".into(), Internal::Global(INDEX_GLOBAL_ABORT)))
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const(0)])))
			.with_export(ExportEntry::new("EXITSTATUS".into(), Internal::Global(INDEX_GLOBAL_EXIT_STATUS)))
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(DEFAULT_TABLE_BASE as i32)]))) // TODO: what is this?
			.with_export(ExportEntry::new("tableBase".into(), Internal::Global(INDEX_GLOBAL_TABLE_BASE)))
		// functions
		.function()
			.signature().build()
			.body().with_opcodes(Opcodes::new(vec![Opcode::Unreachable, Opcode::End])).build()
			.build()
			.with_export(ExportEntry::new("abort".into(), Internal::Function(INDEX_FUNC_ABORT)))
		.function()
			.signature().param().i32().build()
			.body().with_opcodes(Opcodes::new(vec![Opcode::Unreachable, Opcode::End])).build()
			.build()
			.with_export(ExportEntry::new("assert".into(), Internal::Function(INDEX_FUNC_ASSERT)))
		.function()
			.signature().return_type().i32().build()
			.body().with_opcodes(Opcodes::new(vec![Opcode::Unreachable, Opcode::End])).build()
			.build()
			.with_export(ExportEntry::new("enlargeMemory".into(), Internal::Function(INDEX_FUNC_ENLARGE_MEMORY)))
		.function()
			.signature().return_type().i32().build()
			.body().with_opcodes(Opcodes::new(vec![Opcode::Unreachable, Opcode::End])).build()
			.build()
			.with_export(ExportEntry::new("getTotalMemory".into(), Internal::Function(INDEX_FUNC_GET_TOTAL_MEMORY)));

	EnvModuleInstance::new(params, builder.build())
}

impl Default for EnvParams {
	fn default() -> Self {
		EnvParams {
			total_stack: DEFAULT_TOTAL_STACK,
			total_memory: DEFAULT_TOTAL_MEMORY,
			allow_memory_growth: DEFAULT_ALLOW_MEMORY_GROWTH,
		}
	}
}

impl EnvParams {
	fn max_memory(&self) -> Option<u32> {
		if self.allow_memory_growth { None } else { Some(self.total_memory) }
	}
}
<commit_msg>add memoryBase global to env module<commit_after>use std::sync::{Arc, Weak};
use std::collections::HashMap;
use builder::module;
use elements::{Module, ExportEntry, Internal, GlobalEntry, GlobalType,
	ValueType, InitExpr, Opcode, Opcodes};
use interpreter::Error;
use interpreter::env_native::NATIVE_INDEX_FUNC_MIN;
use interpreter::module::{ModuleInstanceInterface, ModuleInstance, ExecutionParams,
	ItemIndex, CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature};
use interpreter::memory::{MemoryInstance, LINEAR_MEMORY_PAGE_SIZE};
use interpreter::table::TableInstance;
use interpreter::value::RuntimeValue;
use interpreter::variable::{VariableInstance, VariableType};

/// Memory address, at which stack begins.
const DEFAULT_STACK_BASE: u32 = 0;
/// Memory, allocated for stack.
const DEFAULT_TOTAL_STACK: u32 = 5 * 1024 * 1024;
/// Total memory, allocated by default.
const DEFAULT_TOTAL_MEMORY: u32 = 16 * 1024 * 1024;
/// Whether memory can be enlarged, or not.
const DEFAULT_ALLOW_MEMORY_GROWTH: bool = false;
/// Default tableBase variable value.
const DEFAULT_TABLE_BASE: u32 = 0;
/// Default tableBase variable value.
const DEFAULT_MEMORY_BASE: u32 = 0;

/// Defaul table size.
const DEFAULT_TABLE_SIZE: u32 = 16;

/// Index of default memory.
const INDEX_MEMORY: u32 = 0;

/// Index of default table.
const INDEX_TABLE: u32 = 0;

/// Index of STACK_BASE global variable.
const INDEX_GLOBAL_STACK_BASE: u32 = 0;
/// Index of STACK_TOP global variable.
const INDEX_GLOBAL_STACK_TOP: u32 = 1;
/// Index of STACK_MAX global variable.
const INDEX_GLOBAL_STACK_MAX: u32 = 2;
/// Index of DYNAMIC_BASE global variable.
const INDEX_GLOBAL_DYNAMIC_BASE: u32 = 3;
/// Index of DYNAMICTOP_PTR global variable.
const INDEX_GLOBAL_DYNAMICTOP_PTR: u32 = 4;
/// Index of TOTAL_MEMORY global variable.
const INDEX_GLOBAL_TOTAL_MEMORY: u32 = 5;
/// Index of ABORT global variable.
const INDEX_GLOBAL_ABORT: u32 = 6;
/// Index of EXITSTATUS global variable.
const INDEX_GLOBAL_EXIT_STATUS: u32 = 7;
/// Index of tableBase global variable.
const INDEX_GLOBAL_TABLE_BASE: u32 = 8;
/// Index of memoryBase global.
const INDEX_GLOBAL_MEMORY_BASE: u32 = 9;

/// Index of abort function.
const INDEX_FUNC_ABORT: u32 = 0;
/// Index of assert function.
const INDEX_FUNC_ASSERT: u32 = 1;
/// Index of enlargeMemory function.
const INDEX_FUNC_ENLARGE_MEMORY: u32 = 2;
/// Index of getTotalMemory function.
const INDEX_FUNC_GET_TOTAL_MEMORY: u32 = 3;
/// Min index of reserver function.
const INDEX_FUNC_MIN_NONUSED: u32 = 4;
/// Max index of reserved function.
const INDEX_FUNC_MAX: u32 = NATIVE_INDEX_FUNC_MIN - 1;

/// Environment parameters.
pub struct EnvParams {
	/// Stack size in bytes.
	pub total_stack: u32,
	/// Total memory size in bytes.
	pub total_memory: u32,
	/// Allow memory growth.
	pub allow_memory_growth: bool,
}

pub struct EnvModuleInstance {
	_params: EnvParams,
	instance: ModuleInstance,
}

impl EnvModuleInstance {
	pub fn new(params: EnvParams, module: Module) -> Result<Self, Error> {
		let instance = ModuleInstance::new(Weak::default(), "env".into(), module)?;

		Ok(EnvModuleInstance {
			_params: params,
			instance: instance,
		})
	}
}

impl ModuleInstanceInterface for EnvModuleInstance {
	fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
		self.instance.execute_index(index, params)
	}

	fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
		self.instance.execute_export(name, params)
	}

	fn export_entry<'a>(&self, name: &str, required_type: &ExportEntryType) -> Result<Internal, Error> {
		self.instance.export_entry(name, required_type)
	}

	fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
		self.instance.table(index)
	}

	fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error> {
		self.instance.memory(index)
	}

	fn global(&self, index: ItemIndex, variable_type: Option<VariableType>) -> Result<Arc<VariableInstance>, Error> {
		self.instance.global(index, variable_type)
	}

	fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, Error> {
		self.instance.function_type(function_index)
	}

	fn function_type_by_index(&self, type_index: u32) -> Result<FunctionSignature, Error> {
		self.instance.function_type_by_index(type_index)
	}

	fn function_reference<'a>(&self, index: ItemIndex, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> {
		self.instance.function_reference(index, externals)
	}

	fn function_reference_indirect<'a>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'a HashMap<String, Arc<ModuleInstanceInterface + 'a>>>) -> Result<InternalFunctionReference<'a>, Error> {
		self.instance.function_reference_indirect(table_idx, type_idx, func_idx, externals)
	}

	fn function_body<'a>(&'a self, _internal_index: u32) -> Result<Option<InternalFunction<'a>>, Error> {
		Ok(None)
	}

	fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result<Option<RuntimeValue>, Error> {
		// to make interpreter independent of *SCRIPTEN runtime, just make abort/assert = interpreter Error
		match index {
			INDEX_FUNC_ABORT => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_ABORT), Some(VariableType::I32))
				.and_then(|g| g.set(RuntimeValue::I32(1)))
				.and_then(|_| Err(Error::Trap("abort".into()))),
			INDEX_FUNC_ASSERT => outer.value_stack.pop_as::<i32>()
				.and_then(|condition| if condition == 0 {
					self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_ABORT), Some(VariableType::I32))
						.and_then(|g| g.set(RuntimeValue::I32(1)))
						.and_then(|_| Err(Error::Trap("assertion failed".into())))
				} else {
					Ok(None)
				}),
			INDEX_FUNC_ENLARGE_MEMORY => Ok(Some(RuntimeValue::I32(0))), // TODO: support memory enlarge
			INDEX_FUNC_GET_TOTAL_MEMORY => self.global(ItemIndex::IndexSpace(INDEX_GLOBAL_TOTAL_MEMORY), Some(VariableType::I32))
				.map(|g| g.get())
				.map(Some),
			INDEX_FUNC_MIN_NONUSED ... INDEX_FUNC_MAX => Err(Error::Trap("unimplemented".into())),
			_ => Err(Error::Trap(format!("trying to call function with index {} in env module", index))),
		}
	}
}

pub fn env_module(params: EnvParams) -> Result<EnvModuleInstance, Error> {
	debug_assert!(params.total_stack < params.total_memory);
	debug_assert!((params.total_stack % LINEAR_MEMORY_PAGE_SIZE) == 0);
	debug_assert!((params.total_memory % LINEAR_MEMORY_PAGE_SIZE) == 0);
	let builder = module()
		// memory regions
		.memory()
			.with_min(params.total_memory / LINEAR_MEMORY_PAGE_SIZE)
			.with_max(params.max_memory().map(|m| m / LINEAR_MEMORY_PAGE_SIZE))
			.build()
			.with_export(ExportEntry::new("memory".into(), Internal::Memory(INDEX_MEMORY)))
		// tables
		.table()
			.with_min(DEFAULT_TABLE_SIZE)
			.build()
			.with_export(ExportEntry::new("table".into(), Internal::Table(INDEX_TABLE)))
		// globals
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(DEFAULT_STACK_BASE as i32)])))
			.with_export(ExportEntry::new("STACK_BASE".into(), Internal::Global(INDEX_GLOBAL_STACK_BASE)))
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const(DEFAULT_STACK_BASE as i32)])))
			.with_export(ExportEntry::new("STACKTOP".into(), Internal::Global(INDEX_GLOBAL_STACK_TOP)))
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const((DEFAULT_STACK_BASE + params.total_stack) as i32)])))
			.with_export(ExportEntry::new("STACK_MAX".into(), Internal::Global(INDEX_GLOBAL_STACK_MAX)))
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const((DEFAULT_STACK_BASE + params.total_stack) as i32)])))
			.with_export(ExportEntry::new("DYNAMIC_BASE".into(), Internal::Global(INDEX_GLOBAL_DYNAMIC_BASE)))
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const((DEFAULT_STACK_BASE + params.total_stack) as i32)])))
			.with_export(ExportEntry::new("DYNAMICTOP_PTR".into(), Internal::Global(INDEX_GLOBAL_DYNAMICTOP_PTR)))
			.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, params.allow_memory_growth), InitExpr::new(vec![Opcode::I32Const(params.total_memory as i32)])))
			.with_export(ExportEntry::new("TOTAL_MEMORY".into(), Internal::Global(INDEX_GLOBAL_TOTAL_MEMORY)))
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const(0)])))
			.with_export(ExportEntry::new("ABORT".into(), Internal::Global(INDEX_GLOBAL_ABORT)))
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const(0)])))
			.with_export(ExportEntry::new("EXITSTATUS".into(), Internal::Global(INDEX_GLOBAL_EXIT_STATUS)))
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(DEFAULT_TABLE_BASE as i32)]))) // TODO: what is this?
			.with_export(ExportEntry::new("tableBase".into(), Internal::Global(INDEX_GLOBAL_TABLE_BASE)))
		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(DEFAULT_MEMORY_BASE as i32)]))) // TODO: what is this?
			.with_export(ExportEntry::new("memoryBaseBase".into(), Internal::Global(INDEX_GLOBAL_MEMORY_BASE)))
		// functions
		.function()
			.signature().build()
			.body().with_opcodes(Opcodes::new(vec![Opcode::Unreachable, Opcode::End])).build()
			.build()
			.with_export(ExportEntry::new("abort".into(), Internal::Function(INDEX_FUNC_ABORT)))
		.function()
			.signature().param().i32().build()
			.body().with_opcodes(Opcodes::new(vec![Opcode::Unreachable, Opcode::End])).build()
			.build()
			.with_export(ExportEntry::new("assert".into(), Internal::Function(INDEX_FUNC_ASSERT)))
		.function()
			.signature().return_type().i32().build()
			.body().with_opcodes(Opcodes::new(vec![Opcode::Unreachable, Opcode::End])).build()
			.build()
			.with_export(ExportEntry::new("enlargeMemory".into(), Internal::Function(INDEX_FUNC_ENLARGE_MEMORY)))
		.function()
			.signature().return_type().i32().build()
			.body().with_opcodes(Opcodes::new(vec![Opcode::Unreachable, Opcode::End])).build()
			.build()
			.with_export(ExportEntry::new("getTotalMemory".into(), Internal::Function(INDEX_FUNC_GET_TOTAL_MEMORY)));

	EnvModuleInstance::new(params, builder.build())
}

impl Default for EnvParams {
	fn default() -> Self {
		EnvParams {
			total_stack: DEFAULT_TOTAL_STACK,
			total_memory: DEFAULT_TOTAL_MEMORY,
			allow_memory_growth: DEFAULT_ALLOW_MEMORY_GROWTH,
		}
	}
}

impl EnvParams {
	fn max_memory(&self) -> Option<u32> {
		if self.allow_memory_growth { None } else { Some(self.total_memory) }
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub mod x_less_y;
pub mod x_eq_y;
pub mod x_neq_y;
<commit_msg>Implements propagator views and tests. Related to #5.<commit_after>// Copyright 2015 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub mod x_less_y;
pub mod x_eq_y;
pub mod x_neq_y;

use num::PrimInt;
use interval::ncollections::ops::*;
use variable::arithmetics::*;
pub use propagators::cmp::x_less_y::XLessY;
pub use propagators::cmp::x_eq_y::XEqY;
pub use propagators::cmp::x_neq_y::XNeqY;

pub fn x_greater_y<X, Y>(x: X, y: Y) -> XLessY<Y, X> {
  XLessY::new(y, x)
}

pub fn x_geq_y<X, Y, R, BX>(x: X, y: Y) -> XLessY<Y, Addition<X, BX>> where
  X: ExprInference<Output=R>,
  R: Bounded<Bound=BX>,
  BX: PrimInt
{
  x_greater_y(Addition::new(x, BX::one()), y)
}

pub fn x_leq_y<X, Y, R, BX>(x: X, y: Y) -> XLessY<Addition<X, BX>, Y> where
  X: ExprInference<Output=R>,
  R: Bounded<Bound=BX>,
  BX: PrimInt
{
  XLessY::new(Addition::new(x, BX::one()), y)
}

#[cfg(test)]
mod test {
  use super::*;
  use kernel::*;
  use kernel::Trilean::*;
  use solver::fd::event::*;
  use solver::fd::event::FDEvent::*;
  use interval::interval::*;
  use propagators::test::*;

  #[test]
  fn x_greater_y_test() {
    let dom0_10 = (0,10).to_interval();
    let dom10_20 = (10,20).to_interval();
    let dom10_11 = (10,11).to_interval();
    let dom5_15 = (5,15).to_interval();
    let dom5_11 = (5,11).to_interval();
    let dom11_20 = (11,20).to_interval();
    let dom9_9 = (9,9).to_interval();

    x_greater_y_test_one(1, dom0_10, dom0_10, Unknown, Unknown, vec![(0, Bound), (1, Bound)], true);
    x_greater_y_test_one(2, dom0_10, dom10_20, False, False, vec![], false);
    x_greater_y_test_one(3, dom5_15, dom10_20, Unknown, Unknown, vec![(0, Bound), (1, Bound)], true);
    x_greater_y_test_one(4, dom5_11, dom10_20, Unknown, True, vec![(0, Assignment), (1, Assignment)], true);
    x_greater_y_test_one(5, dom10_11, dom10_11, Unknown, True, vec![(0, Assignment), (1, Assignment)], true);
    x_greater_y_test_one(6, dom5_15, dom0_10, Unknown, Unknown, vec![], true);
    x_greater_y_test_one(7, dom11_20, dom0_10, True, True, vec![], true);
    x_greater_y_test_one(8, dom9_9, dom0_10, Unknown, True, vec![(1, Bound)], true);
  }

  fn x_greater_y_test_one(test_num: u32, x: Interval<i32>, y: Interval<i32>,
    before: Trilean, after: Trilean,
    delta_expected: Vec<(usize, FDEvent)>, propagate_success: bool)
  {
    binary_propagator_test(test_num, x_greater_y, x, y, before, after, delta_expected, propagate_success);
  }

  #[test]
  fn x_geq_y_test() {
    let dom0_10 = (0,10).to_interval();
    let dom10_20 = (10,20).to_interval();
    let dom10_11 = (10,11).to_interval();
    let dom5_15 = (5,15).to_interval();
    let dom11_20 = (11,20).to_interval();
    let dom9_9 = (9,9).to_interval();

    x_geq_y_test_one(1, dom0_10, dom0_10, Unknown, Unknown, vec![], true);
    x_geq_y_test_one(2, dom0_10, dom10_20, Unknown, True, vec![(0, Assignment), (1, Assignment)], true);
    x_geq_y_test_one(3, dom5_15, dom10_20, Unknown, Unknown, vec![(0, Bound), (1, Bound)], true);
    x_geq_y_test_one(4, dom10_11, dom10_11, Unknown, Unknown, vec![], true);
    x_geq_y_test_one(5, dom5_15, dom0_10, Unknown, Unknown, vec![], true);
    x_geq_y_test_one(6, dom11_20, dom0_10, True, True, vec![], true);
    x_geq_y_test_one(7, dom9_9, dom0_10, Unknown, True, vec![(1, Bound)], true);
  }

  fn x_geq_y_test_one(test_num: u32, x: Interval<i32>, y: Interval<i32>,
    before: Trilean, after: Trilean,
    delta_expected: Vec<(usize, FDEvent)>, propagate_success: bool)
  {
    binary_propagator_test(test_num, x_geq_y, x, y, before, after, delta_expected, propagate_success);
  }
}
<|endoftext|>


<commit_before>use std::iter::Iterator;
use std::iter::Enumerate;
use std::str::Chars;
use parser::literal::LITERAL_EXPRESSION;

mod literal;
mod not;
mod and;
mod char_class;
mod dot;
mod test_utils;

#[deriving(Eq)]
enum NodeContents {
  Text( ~str ),
  Children( ~[ ~Node ] ),
  Empty
}

#[deriving(Eq)]
struct Node {
  name: &'static str,
  start: uint,
  end: uint,
  contents: NodeContents
}

impl Node {
  fn matchedText( &self ) -> ~str {
    match self.contents {
      Empty => ~"",
      Text( ref x ) => x.to_owned(),

      // TODO: recurse through children and collect all text
      Children( _ ) => ~"foo"
    }
  }

  fn predicate( name: &'static str ) -> Node {
    Node { name: name, start: 0, end: 0, contents: Empty }
  }
}

type ParseState<'a> = Enumerate< Chars<'a> >;

struct ParseResult<'a> {
  nodes: ~[ Node ],
  parse_state: ParseState<'a>
}

impl<'a> ParseResult<'a> {
  fn oneNode<'a>( node: Node, parse_state: ParseState<'a> ) -> ParseResult<'a> {
    ParseResult { nodes: ~[ node ], parse_state: parse_state }
  }

  fn manyNodes<'a>( nodes: ~[ Node ], parse_state: ParseState<'a> )
      -> ParseResult<'a> {
    ParseResult { nodes: nodes, parse_state: parse_state }
  }
}

trait Expression {
  fn apply<'a>( &self, parse_state: &ParseState<'a> ) -> Option< ParseResult<'a> >;
}

fn MoveForward<B, T: Iterator<B> >( mut iter: T, steps: uint ) -> T {
  for i in range( 0, steps ) {
    iter.next();
  }
  iter
}

pub fn parseString( input: &str ) -> Node {
  Node { name: LITERAL_EXPRESSION,
         start: 0,
         end: 3,
         contents: Text( input.to_owned() ) }
}

<commit_msg>Add comment placeholders for future modules<commit_after>use std::iter::Iterator;
use std::iter::Enumerate;
use std::str::Chars;
use parser::literal::LITERAL_EXPRESSION;

mod literal;
mod not;
mod and;
mod char_class;
mod dot;
// mod option;
// mod star;
// mod plus;
// mod parens;
// mod or;
// mod sequence;
mod test_utils;

#[deriving(Eq)]
enum NodeContents {
  Text( ~str ),
  Children( ~[ ~Node ] ),
  Empty
}

#[deriving(Eq)]
struct Node {
  name: &'static str,
  start: uint,
  end: uint,
  contents: NodeContents
}

impl Node {
  fn matchedText( &self ) -> ~str {
    match self.contents {
      Empty => ~"",
      Text( ref x ) => x.to_owned(),

      // TODO: recurse through children and collect all text
      Children( _ ) => ~"foo"
    }
  }

  fn predicate( name: &'static str ) -> Node {
    Node { name: name, start: 0, end: 0, contents: Empty }
  }
}

type ParseState<'a> = Enumerate< Chars<'a> >;

struct ParseResult<'a> {
  nodes: ~[ Node ],
  parse_state: ParseState<'a>
}

impl<'a> ParseResult<'a> {
  fn oneNode<'a>( node: Node, parse_state: ParseState<'a> ) -> ParseResult<'a> {
    ParseResult { nodes: ~[ node ], parse_state: parse_state }
  }

  fn manyNodes<'a>( nodes: ~[ Node ], parse_state: ParseState<'a> )
      -> ParseResult<'a> {
    ParseResult { nodes: nodes, parse_state: parse_state }
  }
}

trait Expression {
  fn apply<'a>( &self, parse_state: &ParseState<'a> ) -> Option< ParseResult<'a> >;
}

fn MoveForward<B, T: Iterator<B> >( mut iter: T, steps: uint ) -> T {
  for i in range( 0, steps ) {
    iter.next();
  }
  iter
}

pub fn parseString( input: &str ) -> Node {
  Node { name: LITERAL_EXPRESSION,
         start: 0,
         end: 3,
         contents: Text( input.to_owned() ) }
}

<|endoftext|>


<commit_before>//! This module holds the machinery behind LabelledGeneric.
//!
//! A LabelledGeneric instance is pretty much exactly the same as a Generic instance, except
//! that the generic representation should contain information about field names.
//!
//! Having a separate trait for LabelledGenerics gives us the freedom to derive both
//! lablled and non-labelled generic type class instances for our types.
//!
//! Asides from the main LabelledGeneric trait, this module holds helper methods that allow
//! users to use LabelledGeneric without using universal function call syntax.
//!
//! In addition, this module holds macro-generated enums that map to letters in field names (identifiers).
//!
/// ```
/// # #[macro_use] extern crate frunk_core;
/// # use frunk_core::labelled::*;
/// # use frunk_core::hlist::*;
/// # fn main() {
/// let labelled = label![(n,a,m,e), "Lloyd"];
/// assert_eq!(labelled.name, "name")
/// # }
/// ```

use std::marker::PhantomData;
use hlist::*;
use std::fmt;

/// A trait that converts from a type to a labelled generic representation
///
/// For the most part, you should be using the derivation that is available through
/// frunk_derive to generate instances of this typeclass for your types.
///
/// I would highly recommend you check out `derivation_tests.rs` to see how to actually use
/// this trait in real life. Since frunk_derive depends on this trait, I can't actually
/// pull it in as a dependency here (otherwise the dependency would be circular) and show
/// how to use it in a proper doc test.
///
/// ```rust,ignore
/// #[derive(LabelledGeneric)]
/// struct NewUser<'a> {
///     first_name: &'a str,
///     last_name: &'a str,
///     age: usize,
/// }
///
/// #[derive(LabelledGeneric)]
/// struct SavedUser<'a> {
///     first_name: &'a str,
///     last_name: &'a str,
///     age: usize,
/// }
///
/// let n_user = NewUser {
///     first_name: "Joe",
///     last_name: "Blow",
///     age: 30,
/// };
///
/// let s_user = <SavedUser as LabelledGeneric>::convert_from(n_user); // done
/// ```
pub trait LabelledGeneric {
    /// The labelled generic representation type
    type Repr;

    /// Go from something to Repr
    fn into(self) -> Self::Repr;

    /// Go from labelled Repr to something
    fn from(r: Self::Repr) -> Self;

    /// From one type to another using a type with a compatible labelled generic representation
    fn convert_from<A>(a: A) -> Self
        where A: LabelledGeneric<Repr = Self::Repr>,
              Self: Sized
    {
        let repr = <A as LabelledGeneric>::into(a);
        <Self as LabelledGeneric>::from(repr)
    }

    /// Converts from another type A into Self assuming that A and Self have labelled generic representations
    /// that can be sculpted into each other.
    ///
    /// Note that this method tosses away the "remainder" of the sculpted representation. In other
    /// words, anything that is not needed from A gets tossed out.
    fn sculpted_convert_from<A, Indices>(a: A) -> Self
        where A: LabelledGeneric,
              Self: Sized,
    // The labelled representation of A must be sculpt-able into the labelled representation of Self
              <A as LabelledGeneric>::Repr: Sculptor<<Self as LabelledGeneric>::Repr, Indices> {
        let a_gen = <A as LabelledGeneric>::into(a);
        // We toss away the remainder.
        let (self_gen, _): (<Self as LabelledGeneric>::Repr, _) = a_gen.sculpt();
        <Self as LabelledGeneric>::from(self_gen)
    }
}

/// Given a labelled generic Representation of an A, returns A
pub fn from_labelled_generic<A, Repr>(gen: Repr) -> A
    where A: LabelledGeneric<Repr = Repr>
{
    <A as LabelledGeneric>::from(gen)
}

/// Given an A, returns its labelled generic Representation
pub fn into_labelled_generic<A, Repr>(a: A) -> Repr
    where A: LabelledGeneric<Repr = Repr>
{
    <A as LabelledGeneric>::into(a)
}

/// Converts one type into another assuming they have the same labelled generic Representation
pub fn labelled_convert_from<A, B, Repr>(a: A) -> B
    where A: LabelledGeneric<Repr = Repr>,
          B: LabelledGeneric<Repr = Repr>
{
    <B as LabelledGeneric>::convert_from(a)
}

/// Converts from one type into another assuming that their labelled generic representations
/// can be sculpted into each other.
///
/// The "Indices" type parameter allows the compiler to figure out that the two representations
/// can indeed be morphed into each other.
pub fn sculpted_convert_from<A, B, Indices>(a: A) -> B
    where A: LabelledGeneric,
          B: LabelledGeneric,
// The labelled representation of A must be sculpt-able into the labelled representation of B
          <A as LabelledGeneric>::Repr: Sculptor<<B as LabelledGeneric>::Repr, Indices> {
    <B as LabelledGeneric>::sculpted_convert_from(a)
}

// Create a bunch of enums that can be used to represent characters on the type level
macro_rules! create_enums_for {
    ($($i: ident)*) => {
        $(
            #[allow(non_snake_case, non_camel_case_types)]
            #[derive(PartialEq, Debug, Eq, Clone, Copy, PartialOrd, Ord)]
            pub enum $i {}
        )*
    }
}

// Add more as needed.
create_enums_for! { a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z __ _1 _2 _3 _4 _5 _6 _7 _8 _9 _0 }

/// A Label contains a type-level Name, a runtime value, and
/// a reference to a `&'static str` name.
///
/// To construct one, use the `label!` macro.
///
/// ```
/// # #[macro_use] extern crate frunk_core;
/// # use frunk_core::labelled::*;
/// # use frunk_core::hlist::*;
/// # fn main() {
/// let labelled = label![(n,a,m,e), "joe"];
/// assert_eq!(labelled.name, "name")
/// # }
/// ```
#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
pub struct Labelled<Name, Type> {
    name_type_holder: PhantomData<Name>,
    pub name: &'static str,
    pub value: Type,
}

impl <Name, Type> fmt::Debug for Labelled<Name, Type>
    where Type: fmt::Debug {

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let v_debug = format!("{:?}", self.value);
        write!(f, "Labelled{{ name: {}, value: {} }}", self.name, v_debug)
    }
}

/// Returns a new label for a given value and custom name.
///
/// If you don't want to provide a custom name and want to rely on the type you provide
/// to build a name, then please use the label! macro.
///
/// ```
/// # use frunk_core::labelled::*;
/// let l = label_with_name::<(n,a,m,e),_>("name", "joe");
/// assert_eq!(l.value, "joe");
/// assert_eq!(l.name, "name");
/// ```
pub fn label_with_name<Label, Value>(name: &'static str, value: Value) -> Labelled<Label, Value> {
    Labelled {
        name_type_holder: PhantomData,
        name: name,
        value: value,
    }
}

/// Trait for turning a Labelled HList into an un-labelled HList
pub trait IntoUnlabelled {
    type Output;

    /// Turns the current HList into an unlabelled on.
    ///
    /// Effectively extracts the values held inside the individual Labelled
    ///
    /// ```
    /// # #[macro_use] extern crate frunk_core;
    /// # use frunk_core::labelled::*;
    /// # use frunk_core::hlist::*;
    /// # fn main() {
    ///
    /// let labelled_hlist = hlist![
    ///     label!((n, a, m, e), "joe"),
    ///     label!((a, g, e), 3)
    /// ];
    ///
    /// let unlabelled = labelled_hlist.into_unlabelled();
    ///
    /// assert_eq!(unlabelled, hlist!["joe", 3])
    /// # }
    /// ```
    fn into_unlabelled(self) -> Self::Output;
}

/// Implementation for HNil
impl IntoUnlabelled for HNil {
    type Output = HNil;
    fn into_unlabelled(self) -> Self::Output {
        self
    }
}

/// Implementation when we have a non-empty HCons holding a label in its head
impl<Label, Value, Tail> IntoUnlabelled for HCons<Labelled<Label, Value>, Tail>
    where Tail: IntoUnlabelled
{
    type Output = HCons<Value, <Tail as IntoUnlabelled>::Output>;

    fn into_unlabelled(self) -> Self::Output {
        HCons {
            head: self.head.value,
            tail: self.tail.into_unlabelled(),
        }
    }
}

/// Used for creating a Labelled value
///
/// There are two forms of this macro:
///
/// * Create an instance of the `Labelled` struct with the name
///   set to the the concatenation of the types passed in the
///   tuple used as the first argument.
///
/// ```
/// # #[macro_use] extern crate frunk_core;
/// # use frunk_core::labelled::*;
/// # use frunk_core::hlist::*;
/// # fn main() {
/// let labelled = label![(n,a,m,e), "joe"];
/// assert_eq!(labelled.name, "name")
/// # }
/// ```
///
/// * Create an instance of the `Labelled` struct with a custom, name,
///   passed as the last argument in the macro
/// ```
/// # #[macro_use] extern crate frunk_core;
/// # use frunk_core::labelled::*;
/// # use frunk_core::hlist::*;
/// # fn main() {
/// let labelled = label![(a,g,e), 30, "Age"];
/// assert_eq!(labelled.name, "Age");
/// # }
/// ```
#[macro_export]
macro_rules! label {
    // No name provided and type is a tuple
    (($($repeated: ty),*), $value: expr) => {
        label!( ($($repeated),*), $value, concat!( $(stringify!($repeated)),* ) )
    };
    // No name provided and type is a tuple, but with trailing commas
    (($($repeated: ty,)*), $value: expr) => {
        label!( ($($repeated),*), $value )
    };
    // We are provided any type, with a stable name
    ($name_type: ty, $value: expr, $name: expr) => {
        $crate::labelled::label_with_name::<$name_type,_>($name, $value)
    }
}

#[test]
fn test_label_new_building() {
    let l1 = label!((a, b, c), 3);
    assert_eq!(l1.value, 3);
    assert_eq!(l1.name, "abc");
    let l2 = label!((a, b, c,), 3);
    assert_eq!(l2.value, 3);
    assert_eq!(l2.name, "abc");

    // test named
    let l3 = label!((a,b,c), 3, "nope");
    assert_eq!(l3.value, 3);
    assert_eq!(l3.name, "nope");
    let l4 = label!((a,b,c,), 3, "nope");
    assert_eq!(l4.value, 3);
    assert_eq!(l4.name, "nope");
}

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

    #[test]
    fn test_field_construction() {
        let f1 = label!((a, g, e), 3);
        let f2 = label!((a, g, e), 3);
        assert_eq!(f1, f2)
    }

    #[test]
    fn test_anonymous_record_useage() {
        let record = hlist![
            label!((n, a, m, e), "Joe"),
            label!((a, g, e), 30)
        ];
        let (name, _): (Labelled<(n, a, m, e), _>, _) = record.pluck();
        assert_eq!(name.value, "Joe")
    }

    #[test]
    fn test_unlabelling() {
        let labelled_hlist = hlist![
            label!((n, a, m, e), "joe"),
            label!((a, g, e), 3)];
        let unlabelled = labelled_hlist.into_unlabelled();
        assert_eq!(unlabelled, hlist!["joe", 3])
    }

    #[test]
    fn test_name() {
        let labelled = label!((n, a, m, e), "joe");
        assert_eq!(labelled.name, "name")
    }
}
<commit_msg>Fix code example<commit_after>//! This module holds the machinery behind LabelledGeneric.
//!
//! A LabelledGeneric instance is pretty much exactly the same as a Generic instance, except
//! that the generic representation should contain information about field names.
//!
//! Having a separate trait for LabelledGenerics gives us the freedom to derive both
//! lablled and non-labelled generic type class instances for our types.
//!
//! Asides from the main LabelledGeneric trait, this module holds helper methods that allow
//! users to use LabelledGeneric without using universal function call syntax.
//!
//! In addition, this module holds macro-generated enums that map to letters in field names (identifiers).
//!
/// ```
/// # #[macro_use] extern crate frunk_core;
/// # use frunk_core::labelled::*;
/// # use frunk_core::hlist::*;
/// # fn main() {
/// let labelled = label![(n,a,m,e), "Lloyd"];
/// assert_eq!(labelled.name, "name")
/// # }
/// ```

use std::marker::PhantomData;
use hlist::*;
use std::fmt;

/// A trait that converts from a type to a labelled generic representation
///
/// For the most part, you should be using the derivation that is available through
/// frunk_derive to generate instances of this typeclass for your types.
///
/// I would highly recommend you check out `derivation_tests.rs` to see how to actually use
/// this trait in real life. Since frunk_derive depends on this trait, I can't actually
/// pull it in as a dependency here (otherwise the dependency would be circular) and show
/// how to use it in a proper doc test.
///
/// ```rust,ignore
/// #[derive(LabelledGeneric)]
/// struct NewUser<'a> {
///     first_name: &'a str,
///     last_name: &'a str,
///     age: usize,
/// }
///
/// #[derive(LabelledGeneric)]
/// struct SavedUser<'a> {
///     first_name: &'a str,
///     last_name: &'a str,
///     age: usize,
/// }
///
/// let n_user = NewUser {
///     first_name: "Joe",
///     last_name: "Blow",
///     age: 30,
/// };
///
/// let s_user = <SavedUser as LabelledGeneric>::sculpted_convert_from(n_user); // done
/// ```
pub trait LabelledGeneric {
    /// The labelled generic representation type
    type Repr;

    /// Go from something to Repr
    fn into(self) -> Self::Repr;

    /// Go from labelled Repr to something
    fn from(r: Self::Repr) -> Self;

    /// From one type to another using a type with a compatible labelled generic representation
    fn convert_from<A>(a: A) -> Self
        where A: LabelledGeneric<Repr = Self::Repr>,
              Self: Sized
    {
        let repr = <A as LabelledGeneric>::into(a);
        <Self as LabelledGeneric>::from(repr)
    }

    /// Converts from another type A into Self assuming that A and Self have labelled generic representations
    /// that can be sculpted into each other.
    ///
    /// Note that this method tosses away the "remainder" of the sculpted representation. In other
    /// words, anything that is not needed from A gets tossed out.
    fn sculpted_convert_from<A, Indices>(a: A) -> Self
        where A: LabelledGeneric,
              Self: Sized,
    // The labelled representation of A must be sculpt-able into the labelled representation of Self
              <A as LabelledGeneric>::Repr: Sculptor<<Self as LabelledGeneric>::Repr, Indices> {
        let a_gen = <A as LabelledGeneric>::into(a);
        // We toss away the remainder.
        let (self_gen, _): (<Self as LabelledGeneric>::Repr, _) = a_gen.sculpt();
        <Self as LabelledGeneric>::from(self_gen)
    }
}

/// Given a labelled generic Representation of an A, returns A
pub fn from_labelled_generic<A, Repr>(gen: Repr) -> A
    where A: LabelledGeneric<Repr = Repr>
{
    <A as LabelledGeneric>::from(gen)
}

/// Given an A, returns its labelled generic Representation
pub fn into_labelled_generic<A, Repr>(a: A) -> Repr
    where A: LabelledGeneric<Repr = Repr>
{
    <A as LabelledGeneric>::into(a)
}

/// Converts one type into another assuming they have the same labelled generic Representation
pub fn labelled_convert_from<A, B, Repr>(a: A) -> B
    where A: LabelledGeneric<Repr = Repr>,
          B: LabelledGeneric<Repr = Repr>
{
    <B as LabelledGeneric>::convert_from(a)
}

/// Converts from one type into another assuming that their labelled generic representations
/// can be sculpted into each other.
///
/// The "Indices" type parameter allows the compiler to figure out that the two representations
/// can indeed be morphed into each other.
pub fn sculpted_convert_from<A, B, Indices>(a: A) -> B
    where A: LabelledGeneric,
          B: LabelledGeneric,
// The labelled representation of A must be sculpt-able into the labelled representation of B
          <A as LabelledGeneric>::Repr: Sculptor<<B as LabelledGeneric>::Repr, Indices> {
    <B as LabelledGeneric>::sculpted_convert_from(a)
}

// Create a bunch of enums that can be used to represent characters on the type level
macro_rules! create_enums_for {
    ($($i: ident)*) => {
        $(
            #[allow(non_snake_case, non_camel_case_types)]
            #[derive(PartialEq, Debug, Eq, Clone, Copy, PartialOrd, Ord)]
            pub enum $i {}
        )*
    }
}

// Add more as needed.
create_enums_for! { a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z __ _1 _2 _3 _4 _5 _6 _7 _8 _9 _0 }

/// A Label contains a type-level Name, a runtime value, and
/// a reference to a `&'static str` name.
///
/// To construct one, use the `label!` macro.
///
/// ```
/// # #[macro_use] extern crate frunk_core;
/// # use frunk_core::labelled::*;
/// # use frunk_core::hlist::*;
/// # fn main() {
/// let labelled = label![(n,a,m,e), "joe"];
/// assert_eq!(labelled.name, "name")
/// # }
/// ```
#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
pub struct Labelled<Name, Type> {
    name_type_holder: PhantomData<Name>,
    pub name: &'static str,
    pub value: Type,
}

impl <Name, Type> fmt::Debug for Labelled<Name, Type>
    where Type: fmt::Debug {

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let v_debug = format!("{:?}", self.value);
        write!(f, "Labelled{{ name: {}, value: {} }}", self.name, v_debug)
    }
}

/// Returns a new label for a given value and custom name.
///
/// If you don't want to provide a custom name and want to rely on the type you provide
/// to build a name, then please use the label! macro.
///
/// ```
/// # use frunk_core::labelled::*;
/// let l = label_with_name::<(n,a,m,e),_>("name", "joe");
/// assert_eq!(l.value, "joe");
/// assert_eq!(l.name, "name");
/// ```
pub fn label_with_name<Label, Value>(name: &'static str, value: Value) -> Labelled<Label, Value> {
    Labelled {
        name_type_holder: PhantomData,
        name: name,
        value: value,
    }
}

/// Trait for turning a Labelled HList into an un-labelled HList
pub trait IntoUnlabelled {
    type Output;

    /// Turns the current HList into an unlabelled on.
    ///
    /// Effectively extracts the values held inside the individual Labelled
    ///
    /// ```
    /// # #[macro_use] extern crate frunk_core;
    /// # use frunk_core::labelled::*;
    /// # use frunk_core::hlist::*;
    /// # fn main() {
    ///
    /// let labelled_hlist = hlist![
    ///     label!((n, a, m, e), "joe"),
    ///     label!((a, g, e), 3)
    /// ];
    ///
    /// let unlabelled = labelled_hlist.into_unlabelled();
    ///
    /// assert_eq!(unlabelled, hlist!["joe", 3])
    /// # }
    /// ```
    fn into_unlabelled(self) -> Self::Output;
}

/// Implementation for HNil
impl IntoUnlabelled for HNil {
    type Output = HNil;
    fn into_unlabelled(self) -> Self::Output {
        self
    }
}

/// Implementation when we have a non-empty HCons holding a label in its head
impl<Label, Value, Tail> IntoUnlabelled for HCons<Labelled<Label, Value>, Tail>
    where Tail: IntoUnlabelled
{
    type Output = HCons<Value, <Tail as IntoUnlabelled>::Output>;

    fn into_unlabelled(self) -> Self::Output {
        HCons {
            head: self.head.value,
            tail: self.tail.into_unlabelled(),
        }
    }
}

/// Used for creating a Labelled value
///
/// There are two forms of this macro:
///
/// * Create an instance of the `Labelled` struct with the name
///   set to the the concatenation of the types passed in the
///   tuple used as the first argument.
///
/// ```
/// # #[macro_use] extern crate frunk_core;
/// # use frunk_core::labelled::*;
/// # use frunk_core::hlist::*;
/// # fn main() {
/// let labelled = label![(n,a,m,e), "joe"];
/// assert_eq!(labelled.name, "name")
/// # }
/// ```
///
/// * Create an instance of the `Labelled` struct with a custom, name,
///   passed as the last argument in the macro
/// ```
/// # #[macro_use] extern crate frunk_core;
/// # use frunk_core::labelled::*;
/// # use frunk_core::hlist::*;
/// # fn main() {
/// let labelled = label![(a,g,e), 30, "Age"];
/// assert_eq!(labelled.name, "Age");
/// # }
/// ```
#[macro_export]
macro_rules! label {
    // No name provided and type is a tuple
    (($($repeated: ty),*), $value: expr) => {
        label!( ($($repeated),*), $value, concat!( $(stringify!($repeated)),* ) )
    };
    // No name provided and type is a tuple, but with trailing commas
    (($($repeated: ty,)*), $value: expr) => {
        label!( ($($repeated),*), $value )
    };
    // We are provided any type, with a stable name
    ($name_type: ty, $value: expr, $name: expr) => {
        $crate::labelled::label_with_name::<$name_type,_>($name, $value)
    }
}

#[test]
fn test_label_new_building() {
    let l1 = label!((a, b, c), 3);
    assert_eq!(l1.value, 3);
    assert_eq!(l1.name, "abc");
    let l2 = label!((a, b, c,), 3);
    assert_eq!(l2.value, 3);
    assert_eq!(l2.name, "abc");

    // test named
    let l3 = label!((a,b,c), 3, "nope");
    assert_eq!(l3.value, 3);
    assert_eq!(l3.name, "nope");
    let l4 = label!((a,b,c,), 3, "nope");
    assert_eq!(l4.value, 3);
    assert_eq!(l4.name, "nope");
}

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

    #[test]
    fn test_field_construction() {
        let f1 = label!((a, g, e), 3);
        let f2 = label!((a, g, e), 3);
        assert_eq!(f1, f2)
    }

    #[test]
    fn test_anonymous_record_useage() {
        let record = hlist![
            label!((n, a, m, e), "Joe"),
            label!((a, g, e), 30)
        ];
        let (name, _): (Labelled<(n, a, m, e), _>, _) = record.pluck();
        assert_eq!(name.value, "Joe")
    }

    #[test]
    fn test_unlabelling() {
        let labelled_hlist = hlist![
            label!((n, a, m, e), "joe"),
            label!((a, g, e), 3)];
        let unlabelled = labelled_hlist.into_unlabelled();
        assert_eq!(unlabelled, hlist!["joe", 3])
    }

    #[test]
    fn test_name() {
        let labelled = label!((n, a, m, e), "joe");
        assert_eq!(labelled.name, "name")
    }
}
<|endoftext|>


<commit_before>use super::{GameRenderer, Scene};
use super::animation_data::AnimationData;
use errors::*;

use glm;
use moho::frame_animator::FrameAnimator;
use moho::renderer::Renderer;
use moho::resource_manager::ResourceManager;
use moho::tile_sheet::TileSheet;

use std::time::Duration;

#[derive(Clone)]
pub struct Animation {
    pub dst_rect: glm::IVec4,
    sheet: TileSheet,
    animator: FrameAnimator,
    active: bool,
}

impl Animation {
    pub fn from_data(data: AnimationData, center: glm::IVec2, scale: glm::DVec2) -> Animation {
        let dims = glm::to_ivec2(glm::to_dvec2(data.sheet.dimensions) * scale);
        let dst_rect = glm::ivec4(center.x - dims.x / 2, center.y - dims.y / 2, dims.x, dims.y);
        Self::new(dst_rect, data.sheet.clone(), data.animator)
    }

    pub fn new(dst_rect: glm::IVec4, sheet: TileSheet, animator: FrameAnimator) -> Self {
        Animation {
            dst_rect: dst_rect,
            sheet: sheet,
            animator: animator,
            active: true,
        }
    }

    pub fn update(&mut self, delta: Duration) {
        if self.is_active() {
            self.animator.animate(delta);
            self.active = self.animator.frame() != None;
        } else if self.active {
            self.animator.start();
        }
    }

    pub fn is_active(&self) -> bool {
        self.active && self.animator.frame().is_some()
    }
}

impl<R: Renderer> Scene<ResourceManager<R>> for Animation {
    fn show(&self, renderer: &mut ResourceManager<R>) -> Result<()> {
        if let Some(frame) = self.animator.frame() {
            let tile = self.sheet.tile(frame);
            renderer.render(&tile, self.dst_rect)
        } else {
            Ok(())
        }
    }
}
<commit_msg>minor refactor to animation<commit_after>use super::{GameRenderer, Scene};
use super::animation_data::AnimationData;
use errors::*;

use glm;
use moho::frame_animator::FrameAnimator;
use moho::renderer::Renderer;
use moho::resource_manager::ResourceManager;
use moho::tile_sheet::TileSheet;

use std::time::Duration;

#[derive(Clone)]
pub struct Animation {
    pub dst_rect: glm::IVec4,
    sheet: TileSheet,
    animator: FrameAnimator,
    started: bool,
}

impl Animation {
    pub fn from_data(data: AnimationData, center: glm::IVec2, scale: glm::DVec2) -> Animation {
        let dims = glm::to_ivec2(glm::to_dvec2(data.sheet.dimensions) * scale);
        let dst_rect = glm::ivec4(center.x - dims.x / 2, center.y - dims.y / 2, dims.x, dims.y);
        Self::new(dst_rect, data.sheet.clone(), data.animator)
    }

    pub fn new(dst_rect: glm::IVec4, sheet: TileSheet, animator: FrameAnimator) -> Self {
        Animation {
            dst_rect: dst_rect,
            sheet: sheet,
            animator: animator,
            started: false,
        }
    }

    pub fn update(&mut self, delta: Duration) {
        if !self.started {
            self.animator.start();
            self.started = true;
        } else if self.animator.frame().is_some() {
            self.animator.animate(delta);
        }
    }

    pub fn is_active(&self) -> bool {
        self.animator.frame().is_some()
    }
}

impl<R: Renderer> Scene<ResourceManager<R>> for Animation {
    fn show(&self, renderer: &mut ResourceManager<R>) -> Result<()> {
        if let Some(frame) = self.animator.frame() {
            let tile = self.sheet.tile(frame);
            renderer.render(&tile, self.dst_rect)
        } else {
            Ok(())
        }
    }
}
<|endoftext|>


<commit_before>//! Buffer management for same-process client<->server communication.

use std::io::{self, Write};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::slice;

#[repr(C)]
struct Slice<'a, T> {
    data: &'a [T; 0],
    len: usize,
}

unsafe impl<'a, T: Sync> Sync for Slice<'a, T> {}
unsafe impl<'a, T: Sync> Send for Slice<'a, T> {}

impl<T> Copy for Slice<'a, T> {}
impl<T> Clone for Slice<'a, T> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<T> From<&'a [T]> for Slice<'a, T> {
    fn from(xs: &'a [T]) -> Self {
        Slice { data: unsafe { &*(xs.as_ptr() as *const [T; 0]) }, len: xs.len() }
    }
}

impl<T> Deref for Slice<'a, T> {
    type Target = [T];
    fn deref(&self) -> &[T] {
        unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) }
    }
}

#[repr(C)]
pub struct Buffer<T: Copy> {
    data: *mut T,
    len: usize,
    capacity: usize,
    reserve: extern "C" fn(Buffer<T>, usize) -> Buffer<T>,
    drop: extern "C" fn(Buffer<T>),
}

unsafe impl<T: Copy + Sync> Sync for Buffer<T> {}
unsafe impl<T: Copy + Send> Send for Buffer<T> {}

impl<T: Copy> Default for Buffer<T> {
    fn default() -> Self {
        Self::from(vec![])
    }
}

impl<T: Copy> Deref for Buffer<T> {
    type Target = [T];
    fn deref(&self) -> &[T] {
        unsafe { slice::from_raw_parts(self.data as *const T, self.len) }
    }
}

impl<T: Copy> DerefMut for Buffer<T> {
    fn deref_mut(&mut self) -> &mut [T] {
        unsafe { slice::from_raw_parts_mut(self.data, self.len) }
    }
}

impl<T: Copy> Buffer<T> {
    pub(super) fn new() -> Self {
        Self::default()
    }

    pub(super) fn clear(&mut self) {
        self.len = 0;
    }

    pub(super) fn take(&mut self) -> Self {
        mem::take(self)
    }

    // We have the array method separate from extending from a slice. This is
    // because in the case of small arrays, codegen can be more efficient
    // (avoiding a memmove call). With extend_from_slice, LLVM at least
    // currently is not able to make that optimization.
    pub(super) fn extend_from_array<const N: usize>(&mut self, xs: &[T; N]) {
        if xs.len() > (self.capacity - self.len) {
            let b = self.take();
            *self = (b.reserve)(b, xs.len());
        }
        unsafe {
            xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len());
            self.len += xs.len();
        }
    }

    pub(super) fn extend_from_slice(&mut self, xs: &[T]) {
        if xs.len() > (self.capacity - self.len) {
            let b = self.take();
            *self = (b.reserve)(b, xs.len());
        }
        unsafe {
            xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len());
            self.len += xs.len();
        }
    }

    pub(super) fn push(&mut self, v: T) {
        // The code here is taken from Vec::push, and we know that reserve()
        // will panic if we're exceeding isize::MAX bytes and so there's no need
        // to check for overflow.
        if self.len == self.capacity {
            let b = self.take();
            *self = (b.reserve)(b, 1);
        }
        unsafe {
            *self.data.add(self.len) = v;
            self.len += 1;
        }
    }
}

impl Write for Buffer<u8> {
    fn write(&mut self, xs: &[u8]) -> io::Result<usize> {
        self.extend_from_slice(xs);
        Ok(xs.len())
    }

    fn write_all(&mut self, xs: &[u8]) -> io::Result<()> {
        self.extend_from_slice(xs);
        Ok(())
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl<T: Copy> Drop for Buffer<T> {
    fn drop(&mut self) {
        let b = self.take();
        (b.drop)(b);
    }
}

impl<T: Copy> From<Vec<T>> for Buffer<T> {
    fn from(mut v: Vec<T>) -> Self {
        let (data, len, capacity) = (v.as_mut_ptr(), v.len(), v.capacity());
        mem::forget(v);

        // This utility function is nested in here because it can *only*
        // be safely called on `Buffer`s created by *this* `proc_macro`.
        fn to_vec<T: Copy>(b: Buffer<T>) -> Vec<T> {
            unsafe {
                let Buffer { data, len, capacity, .. } = b;
                mem::forget(b);
                Vec::from_raw_parts(data, len, capacity)
            }
        }

        extern "C" fn reserve<T: Copy>(b: Buffer<T>, additional: usize) -> Buffer<T> {
            let mut v = to_vec(b);
            v.reserve(additional);
            Buffer::from(v)
        }

        extern "C" fn drop<T: Copy>(b: Buffer<T>) {
            mem::drop(to_vec(b));
        }

        Buffer { data, len, capacity, reserve, drop }
    }
}
<commit_msg>Rollup merge of #86785 - lf-:dead-code, r=Mark-Simulacrum<commit_after>//! Buffer management for same-process client<->server communication.

use std::io::{self, Write};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::slice;

#[repr(C)]
pub struct Buffer<T: Copy> {
    data: *mut T,
    len: usize,
    capacity: usize,
    reserve: extern "C" fn(Buffer<T>, usize) -> Buffer<T>,
    drop: extern "C" fn(Buffer<T>),
}

unsafe impl<T: Copy + Sync> Sync for Buffer<T> {}
unsafe impl<T: Copy + Send> Send for Buffer<T> {}

impl<T: Copy> Default for Buffer<T> {
    fn default() -> Self {
        Self::from(vec![])
    }
}

impl<T: Copy> Deref for Buffer<T> {
    type Target = [T];
    fn deref(&self) -> &[T] {
        unsafe { slice::from_raw_parts(self.data as *const T, self.len) }
    }
}

impl<T: Copy> DerefMut for Buffer<T> {
    fn deref_mut(&mut self) -> &mut [T] {
        unsafe { slice::from_raw_parts_mut(self.data, self.len) }
    }
}

impl<T: Copy> Buffer<T> {
    pub(super) fn new() -> Self {
        Self::default()
    }

    pub(super) fn clear(&mut self) {
        self.len = 0;
    }

    pub(super) fn take(&mut self) -> Self {
        mem::take(self)
    }

    // We have the array method separate from extending from a slice. This is
    // because in the case of small arrays, codegen can be more efficient
    // (avoiding a memmove call). With extend_from_slice, LLVM at least
    // currently is not able to make that optimization.
    pub(super) fn extend_from_array<const N: usize>(&mut self, xs: &[T; N]) {
        if xs.len() > (self.capacity - self.len) {
            let b = self.take();
            *self = (b.reserve)(b, xs.len());
        }
        unsafe {
            xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len());
            self.len += xs.len();
        }
    }

    pub(super) fn extend_from_slice(&mut self, xs: &[T]) {
        if xs.len() > (self.capacity - self.len) {
            let b = self.take();
            *self = (b.reserve)(b, xs.len());
        }
        unsafe {
            xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len());
            self.len += xs.len();
        }
    }

    pub(super) fn push(&mut self, v: T) {
        // The code here is taken from Vec::push, and we know that reserve()
        // will panic if we're exceeding isize::MAX bytes and so there's no need
        // to check for overflow.
        if self.len == self.capacity {
            let b = self.take();
            *self = (b.reserve)(b, 1);
        }
        unsafe {
            *self.data.add(self.len) = v;
            self.len += 1;
        }
    }
}

impl Write for Buffer<u8> {
    fn write(&mut self, xs: &[u8]) -> io::Result<usize> {
        self.extend_from_slice(xs);
        Ok(xs.len())
    }

    fn write_all(&mut self, xs: &[u8]) -> io::Result<()> {
        self.extend_from_slice(xs);
        Ok(())
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl<T: Copy> Drop for Buffer<T> {
    fn drop(&mut self) {
        let b = self.take();
        (b.drop)(b);
    }
}

impl<T: Copy> From<Vec<T>> for Buffer<T> {
    fn from(mut v: Vec<T>) -> Self {
        let (data, len, capacity) = (v.as_mut_ptr(), v.len(), v.capacity());
        mem::forget(v);

        // This utility function is nested in here because it can *only*
        // be safely called on `Buffer`s created by *this* `proc_macro`.
        fn to_vec<T: Copy>(b: Buffer<T>) -> Vec<T> {
            unsafe {
                let Buffer { data, len, capacity, .. } = b;
                mem::forget(b);
                Vec::from_raw_parts(data, len, capacity)
            }
        }

        extern "C" fn reserve<T: Copy>(b: Buffer<T>, additional: usize) -> Buffer<T> {
            let mut v = to_vec(b);
            v.reserve(additional);
            Buffer::from(v)
        }

        extern "C" fn drop<T: Copy>(b: Buffer<T>) {
            mem::drop(to_vec(b));
        }

        Buffer { data, len, capacity, reserve, drop }
    }
}
<|endoftext|>


<commit_before>#![crate_type = "bin"]

extern crate cairo;
extern crate pango_sys;
extern crate gdk;
extern crate glib;
extern crate gtk;
extern crate gtk_sys;
extern crate libc;
extern crate sysinfo;

use sysinfo::*;

use gtk::prelude::*;
use gtk::MenuBar;

use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::rc::Rc;

use display_sysinfo::DisplaySysInfo;
use notebook::NoteBook;
use procs::{create_and_fill_model, Procs};

mod color;
mod display_sysinfo;
mod notebook;
mod process_dialog;
mod procs;
mod utils;

fn update_window(list: &gtk::ListStore, system: &Rc<RefCell<sysinfo::System>>,
                 info: &mut DisplaySysInfo) {
    let mut system = system.borrow_mut();
    system.refresh_all();
    info.update_ram_display(&system);
    info.update_process_display(&system);
    let entries: &HashMap<usize, Process> = system.get_process_list();
    let mut seen: HashSet<usize> = HashSet::new();

    if let Some(mut iter) = list.get_iter_first() {
        let mut valid = true;
        while valid {
            let pid = list.get_value(&iter, 0).get::<i64>().unwrap() as usize;
            if let Some(p) = entries.get(&(pid)) {
                list.set(&iter,
                         &[2, 3, 5],
                         &[&format!("{:.1}", p.cpu_usage), &p.memory, &p.cpu_usage]);
                valid = list.iter_next(&mut iter);
                seen.insert(pid);
            } else {
                valid = list.remove(&mut iter);
            }
        }
    }

    for (pid, pro) in entries.iter() {
        if !seen.contains(pid) {
            create_and_fill_model(list, pro.pid, &pro.cmd, &pro.name, pro.cpu_usage, pro.memory);
        }
    }
}

fn main() {
    gtk::init().expect("GTK couldn't start normally");

    let window = gtk::Window::new(gtk::WindowType::Toplevel);
    let sys = sysinfo::System::new();
    let start_time = unsafe { sys.get_process(libc::getpid() as i64).unwrap().start_time };
    let running_since = Rc::new(RefCell::new(0));
    let sys = Rc::new(RefCell::new(sys));
    let mut note = NoteBook::new();
    let procs = Procs::new(sys.borrow().get_process_list(), &mut note);
    let current_pid = procs.current_pid.clone();
    let current_pid2 = procs.current_pid.clone();
    let sys1 = sys.clone();
    let sys2 = sys.clone();
    let sys3 = sys.clone();
    let info_button = procs.info_button.clone();

    window.set_title("Process viewer");
    window.set_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });

    sys.borrow_mut().refresh_all();
    procs.kill_button.connect_clicked(move |_| {
        let sys = sys1.borrow();
        if let Some(process) = current_pid.get().and_then(|pid| sys.get_process(pid)) {
            process.kill(Signal::Kill);
        }
    });

    let mut display_tab = DisplaySysInfo::new(sys.clone(), &mut note, &window);

    let v_box = gtk::Box::new(gtk::Orientation::Vertical, 0);
    let menu_bar = MenuBar::new();
    let menu = gtk::Menu::new();
    let more_menu = gtk::Menu::new();
    let file = gtk::MenuItem::new_with_label("File");
    let new_task = gtk::MenuItem::new_with_label("Launch new executable");
    let quit = gtk::MenuItem::new_with_label("Quit");
    let more = gtk::MenuItem::new_with_label("?");
    let about = gtk::MenuItem::new_with_label("About");

    menu.append(&new_task);
    menu.append(&quit);
    file.set_submenu(Some(&menu));
    menu_bar.append(&file);
    more_menu.append(&about);
    more.set_submenu(Some(&more_menu));
    menu_bar.append(&more);

    v_box.pack_start(&menu_bar, false, false, 0);
    v_box.pack_start(&note.notebook, true, true, 0);

    window.add(&v_box);
    window.show_all();
    let window1 = window.clone();
    let window2 = window.clone();

    let list_store = procs.list_store.clone();
    let run1 = running_since.clone();
    let run2 = running_since.clone();
    gtk::timeout_add(1000, move || {
        *run1.borrow_mut() += 1;
        // first part, deactivate sorting
        let sorted = list_store.get_sort_column_id();
        list_store.set_unsorted();

        // we update the tree view
        update_window(&list_store, &sys, &mut display_tab);

        // we re-enable the sorting
        if let Some((col, order)) = sorted {
            list_store.set_sort_column_id(col, order);
        }
        window1.queue_draw();
        glib::Continue(true)
    });
    info_button.connect_clicked(move |_| {
        let sys = sys2.borrow();
        if let Some(process) = current_pid2.get().and_then(|pid| sys.get_process(pid)) {
            process_dialog::create_process_dialog(&process, &window2, start_time,
                                                  run2.borrow().clone());
        }
    });
    procs.left_tree.connect_row_activated(move |tree_view, path, _| {
        let model = tree_view.get_model().unwrap();
        let iter = model.get_iter(path).unwrap();
        let sys = sys3.borrow();
        if let Some(process) = sys.get_process(model.get_value(&iter, 0).get().unwrap()) {
            process_dialog::create_process_dialog(&process, &window, start_time,
                                                  running_since.borrow().clone());
        }
    });
    quit.connect_activate(|_| {
        gtk::main_quit();
    });

    gtk::main();
}
<commit_msg>Add new window<commit_after>#![crate_type = "bin"]

extern crate cairo;
extern crate pango_sys;
extern crate gdk;
extern crate glib;
extern crate gtk;
extern crate gtk_sys;
extern crate libc;
extern crate sysinfo;

use sysinfo::*;

use gtk::prelude::*;
use gtk::{AboutDialog, Button, Dialog, Entry, MenuBar};

use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::rc::Rc;

use display_sysinfo::DisplaySysInfo;
use notebook::NoteBook;
use procs::{create_and_fill_model, Procs};

mod color;
mod display_sysinfo;
mod notebook;
mod process_dialog;
mod procs;
mod utils;

fn update_window(list: &gtk::ListStore, system: &Rc<RefCell<sysinfo::System>>,
                 info: &mut DisplaySysInfo) {
    let mut system = system.borrow_mut();
    system.refresh_all();
    info.update_ram_display(&system);
    info.update_process_display(&system);
    let entries: &HashMap<usize, Process> = system.get_process_list();
    let mut seen: HashSet<usize> = HashSet::new();

    if let Some(mut iter) = list.get_iter_first() {
        let mut valid = true;
        while valid {
            let pid = list.get_value(&iter, 0).get::<i64>().unwrap() as usize;
            if let Some(p) = entries.get(&(pid)) {
                list.set(&iter,
                         &[2, 3, 5],
                         &[&format!("{:.1}", p.cpu_usage), &p.memory, &p.cpu_usage]);
                valid = list.iter_next(&mut iter);
                seen.insert(pid);
            } else {
                valid = list.remove(&mut iter);
            }
        }
    }

    for (pid, pro) in entries.iter() {
        if !seen.contains(pid) {
            create_and_fill_model(list, pro.pid, &pro.cmd, &pro.name, pro.cpu_usage, pro.memory);
        }
    }
}

fn main() {
    gtk::init().expect("GTK couldn't start normally");

    let window = gtk::Window::new(gtk::WindowType::Toplevel);
    let sys = sysinfo::System::new();
    let start_time = unsafe { sys.get_process(libc::getpid() as i64).unwrap().start_time };
    let running_since = Rc::new(RefCell::new(0));
    let sys = Rc::new(RefCell::new(sys));
    let mut note = NoteBook::new();
    let procs = Procs::new(sys.borrow().get_process_list(), &mut note);
    let current_pid = procs.current_pid.clone();
    let current_pid2 = procs.current_pid.clone();
    let sys1 = sys.clone();
    let sys2 = sys.clone();
    let sys3 = sys.clone();
    let info_button = procs.info_button.clone();

    window.set_title("Process viewer");
    window.set_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });

    sys.borrow_mut().refresh_all();
    procs.kill_button.connect_clicked(move |_| {
        let sys = sys1.borrow();
        if let Some(process) = current_pid.get().and_then(|pid| sys.get_process(pid)) {
            process.kill(Signal::Kill);
        }
    });

    let mut display_tab = DisplaySysInfo::new(sys.clone(), &mut note, &window);

    let v_box = gtk::Box::new(gtk::Orientation::Vertical, 0);
    let menu_bar = MenuBar::new();
    let menu = gtk::Menu::new();
    let more_menu = gtk::Menu::new();
    let file = gtk::MenuItem::new_with_label("File");
    let new_task = gtk::MenuItem::new_with_label("Launch new executable");
    let quit = gtk::MenuItem::new_with_label("Quit");
    let more = gtk::MenuItem::new_with_label("?");
    let about = gtk::MenuItem::new_with_label("About");

    menu.append(&new_task);
    menu.append(&quit);
    file.set_submenu(Some(&menu));
    menu_bar.append(&file);
    more_menu.append(&about);
    more.set_submenu(Some(&more_menu));
    menu_bar.append(&more);

    v_box.pack_start(&menu_bar, false, false, 0);
    v_box.pack_start(&note.notebook, true, true, 0);

    window.add(&v_box);
    window.show_all();
    let window1 = window.clone();
    let window2 = window.clone();

    let list_store = procs.list_store.clone();
    let run1 = running_since.clone();
    let run2 = running_since.clone();
    gtk::timeout_add(1000, move || {
        *run1.borrow_mut() += 1;
        // first part, deactivate sorting
        let sorted = list_store.get_sort_column_id();
        list_store.set_unsorted();

        // we update the tree view
        update_window(&list_store, &sys, &mut display_tab);

        // we re-enable the sorting
        if let Some((col, order)) = sorted {
            list_store.set_sort_column_id(col, order);
        }
        window1.queue_draw();
        glib::Continue(true)
    });
    info_button.connect_clicked(move |_| {
        let sys = sys2.borrow();
        if let Some(process) = current_pid2.get().and_then(|pid| sys.get_process(pid)) {
            process_dialog::create_process_dialog(&process, &window2, start_time,
                                                  run2.borrow().clone());
        }
    });
    let window2 = window.clone();
    procs.left_tree.connect_row_activated(move |tree_view, path, _| {
        let model = tree_view.get_model().unwrap();
        let iter = model.get_iter(path).unwrap();
        let sys = sys3.borrow();
        if let Some(process) = sys.get_process(model.get_value(&iter, 0).get().unwrap()) {
            process_dialog::create_process_dialog(&process, &window2, start_time,
                                                  running_since.borrow().clone());
        }
    });

    quit.connect_activate(|_| {
        gtk::main_quit();
    });
    let window3 = window.clone();
    about.connect_activate(move |_| {
        let p = AboutDialog::new();
        p.set_authors(&["Guillaume Gomez"]);
        p.set_website_label(Some("my website"));
        p.set_website(Some("http://guillaume-gomez.fr/"));
        p.set_comments(Some("A process viewer GUI wrote with gtk-rs"));
        p.set_copyright(Some("This is under MIT license"));
        p.set_transient_for(Some(&window3));
        p.show_all();
    });
    new_task.connect_activate(move |_| {
        let d = Dialog::new();
        d.set_title("Launch new executable");
        let content_area = d.get_content_area();
        let input = Entry::new();
        let run = Button::new_with_label("Run");
        let cancel = Button::new_with_label("Cancel");
        let v_box = gtk::Box::new(gtk::Orientation::Vertical, 0);
        let h_box = gtk::Box::new(gtk::Orientation::Horizontal, 0);
        h_box.pack_start(&run, true, true, 0);
        h_box.pack_start(&cancel, true, true, 0);
        v_box.pack_start(&input, true, true, 0);
        v_box.pack_start(&h_box, true, true, 0);
        content_area.add(&v_box);
        d.set_transient_for(Some(&window));
        d.set_size_request(400, 70);
        d.show_all();

        cancel.connect_clicked(move |_| {
            d.destroy();
        });
    });

    gtk::main();
}
<|endoftext|>


<commit_before>use errors::*;
use notifications::*;
use toml_utils::*;
use utils;
use toml;
use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use std::cell::RefCell;
use std::str::FromStr;

pub const SUPPORTED_METADATA_VERSIONS: [&'static str; 2] = ["2", "12"];
pub const DEFAULT_METADATA_VERSION: &'static str = "12";

#[derive(Clone, Debug, PartialEq)]
pub struct SettingsFile {
    path: PathBuf,
    cache: RefCell<Option<Settings>>
}

impl SettingsFile {
    pub fn new(path: PathBuf) -> Self {
        SettingsFile {
            path: path,
            cache: RefCell::new(None)
        }
    }
    fn write_settings(&self) -> Result<()> {
        let s = self.cache.borrow().as_ref().unwrap().clone();
        try!(utils::write_file("settings", &self.path, &s.stringify()));
        Ok(())
    }
    fn read_settings(&self) -> Result<()> {
        let mut needs_save = false;
        {
            let mut b = self.cache.borrow_mut();
            if b.is_none() {
                *b = Some(if utils::is_file(&self.path) {
                    let content = try!(utils::read_file("settings", &self.path));
                    try!(Settings::parse(&content))
                } else {
                    needs_save = true;
                    Default::default()
                });
            }
        }
        if needs_save {
            try!(self.write_settings());
        }
        Ok(())
    }
    pub fn with<T, F: FnOnce(&Settings) -> Result<T>>(&self, f: F) -> Result<T> {
        try!(self.read_settings());

        // Settings can no longer be None so it's OK to unwrap
        f(self.cache.borrow().as_ref().unwrap())
    }
    pub fn with_mut<T, F: FnOnce(&mut Settings) -> Result<T>>(&self, f: F) -> Result<T> {
        try!(self.read_settings());

        // Settings can no longer be None so it's OK to unwrap
        let result = {
            try!(f(self.cache.borrow_mut().as_mut().unwrap()))
        };
        try!(self.write_settings());
        Ok(result)
    }
    pub fn maybe_upgrade_from_legacy(&self, multirust_dir: &Path) -> Result<()> {
        // Data locations
        let legacy_version_file = multirust_dir.join("version");
        if utils::is_file(&legacy_version_file) {
            fn split_override<T: FromStr>(s: &str, separator: char) -> Option<(T, T)> {
                s.find(separator).and_then(|index| {
                    match (T::from_str(&s[..index]), T::from_str(&s[index + 1..])) {
                        (Ok(l), Ok(r)) => Some((l, r)),
                        _ => None
                    }
                })
            }

            let override_db = multirust_dir.join("overrides");
            let default_file = multirust_dir.join("default");
            let telemetry_file = multirust_dir.join("telemetry-on");
            // Legacy upgrade
            try!(self.with_mut(|s| {
                s.version = try!(utils::read_file("version", &legacy_version_file))
                    .trim().to_owned();

                if utils::is_file(&default_file) {
                    s.default_toolchain = Some(try!(utils::read_file("default", &default_file))
                        .trim().to_owned());
                }
                if utils::is_file(&override_db) {
                    let overrides = try!(utils::read_file("overrides", &override_db));
                    for o in overrides.lines() {
                        if let Some((k, v)) = split_override(o, ';') {
                            s.overrides.insert(k, v);
                        }
                    }
                }
                if utils::is_file(&telemetry_file) {
                    s.telemetry = TelemetryMode::On;
                }
                Ok(())
            }));

            // Failure to delete these is not a fatal error
            let _ = utils::remove_file("version", &legacy_version_file);
            let _ = utils::remove_file("default", &default_file);
            let _ = utils::remove_file("overrides", &override_db);
            let _ = utils::remove_file("telemetry", &telemetry_file);
        }
        Ok(())
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum TelemetryMode {
    On,
    Off,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Settings {
    pub version: String,
    pub default_host_triple: Option<String>,
    pub default_toolchain: Option<String>,
    pub overrides: BTreeMap<String, String>,
    pub telemetry: TelemetryMode
}

impl Default for Settings {
    fn default() -> Self {
        Settings {
            version: DEFAULT_METADATA_VERSION.to_owned(),
            default_host_triple: None,
            default_toolchain: None,
            overrides: BTreeMap::new(),
            telemetry: TelemetryMode::Off
        }
    }
}

impl Settings {
    fn path_to_key(path: &Path, notify_handler: &Fn(Notification)) -> String {
        utils::canonicalize_path(path, &|n| notify_handler(n.into()))
               .display()
               .to_string()
    }

    pub fn remove_override(&mut self, path: &Path, notify_handler: &Fn(Notification)) -> bool {
        let key = Self::path_to_key(path, notify_handler);
        self.overrides.remove(&key).is_some()
    }

    pub fn add_override(&mut self, path: &Path, toolchain: String, notify_handler: &Fn(Notification)) {
        let key = Self::path_to_key(path, notify_handler);
        notify_handler(Notification::SetOverrideToolchain(path, &toolchain));
        self.overrides.insert(key, toolchain);
    }

    pub fn find_override(&self, dir_unresolved: &Path, notify_handler: &Fn(Notification))
            -> Option<(String, PathBuf)> {
        let dir = utils::canonicalize_path(dir_unresolved, &|n| notify_handler(n.into()));
        let mut maybe_path = Some(&*dir);
        while let Some(path) = maybe_path {
            let key = Self::path_to_key(path, notify_handler);
            if let Some(toolchain) = self.overrides.get(&key) {
                return Some((toolchain.to_owned(), path.to_owned()));
            }
            maybe_path = path.parent();
        }
        None
    }

    pub fn parse(data: &str) -> Result<Self> {
        let mut parser = toml::Parser::new(data);
        let value = try!(parser.parse().ok_or_else(move || ErrorKind::ParsingSettings(parser.errors)));

        Self::from_toml(value, "")
    }
    pub fn stringify(self) -> String {
        toml::Value::Table(self.to_toml()).to_string()
    }

    pub fn from_toml(mut table: toml::Table, path: &str) -> Result<Self> {
        let version = try!(get_string(&mut table, "version", path));
        if !SUPPORTED_METADATA_VERSIONS.contains(&&*version) {
            return Err(ErrorKind::UnknownMetadataVersion(version).into());
        }
        Ok(Settings {
            version: version,
            default_host_triple: try!(get_opt_string(&mut table, "default_host_triple", path)),
            default_toolchain: try!(get_opt_string(&mut table, "default_toolchain", path)),
            overrides: try!(Self::table_to_overrides(&mut table, path)),
            telemetry: if try!(get_opt_bool(&mut table, "telemetry", path)).unwrap_or(false) {
                TelemetryMode::On
            } else {
                TelemetryMode::Off
            }
        })
    }
    pub fn to_toml(self) -> toml::Table {
        let mut result = toml::Table::new();

        result.insert("version".to_owned(),
                      toml::Value::String(self.version));

        if let Some(v) = self.default_host_triple {
            result.insert("default_host_triple".to_owned(), toml::Value::String(v));
        }

        if let Some(v) = self.default_toolchain {
            result.insert("default_toolchain".to_owned(), toml::Value::String(v));
        }

        let overrides = Self::overrides_to_table(self.overrides);
        result.insert("overrides".to_owned(), toml::Value::Table(overrides));

        let telemetry = self.telemetry == TelemetryMode::On;
        result.insert("telemetry".to_owned(), toml::Value::Boolean(telemetry));

        result
    }

    fn table_to_overrides(table: &mut toml::Table, path: &str) -> Result<BTreeMap<String, String>> {
        let mut result = BTreeMap::new();
        let pkg_table = try!(get_table(table, "overrides", path));

        for (k, v) in pkg_table {
            if let toml::Value::String(t) = v {
                result.insert(k, t);
            }
        }

        Ok(result)
    }

    fn overrides_to_table(overrides: BTreeMap<String, String>) -> toml::Table {
        let mut result = toml::Table::new();
        for (k, v) in overrides {
            result.insert(k, toml::Value::String(v));
        }
        result
    }
}
<commit_msg>fix canonicalize warning when removing nonexistent path<commit_after>use errors::*;
use notifications::*;
use toml_utils::*;
use utils;
use toml;
use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use std::cell::RefCell;
use std::str::FromStr;

pub const SUPPORTED_METADATA_VERSIONS: [&'static str; 2] = ["2", "12"];
pub const DEFAULT_METADATA_VERSION: &'static str = "12";

#[derive(Clone, Debug, PartialEq)]
pub struct SettingsFile {
    path: PathBuf,
    cache: RefCell<Option<Settings>>
}

impl SettingsFile {
    pub fn new(path: PathBuf) -> Self {
        SettingsFile {
            path: path,
            cache: RefCell::new(None)
        }
    }
    fn write_settings(&self) -> Result<()> {
        let s = self.cache.borrow().as_ref().unwrap().clone();
        try!(utils::write_file("settings", &self.path, &s.stringify()));
        Ok(())
    }
    fn read_settings(&self) -> Result<()> {
        let mut needs_save = false;
        {
            let mut b = self.cache.borrow_mut();
            if b.is_none() {
                *b = Some(if utils::is_file(&self.path) {
                    let content = try!(utils::read_file("settings", &self.path));
                    try!(Settings::parse(&content))
                } else {
                    needs_save = true;
                    Default::default()
                });
            }
        }
        if needs_save {
            try!(self.write_settings());
        }
        Ok(())
    }
    pub fn with<T, F: FnOnce(&Settings) -> Result<T>>(&self, f: F) -> Result<T> {
        try!(self.read_settings());

        // Settings can no longer be None so it's OK to unwrap
        f(self.cache.borrow().as_ref().unwrap())
    }
    pub fn with_mut<T, F: FnOnce(&mut Settings) -> Result<T>>(&self, f: F) -> Result<T> {
        try!(self.read_settings());

        // Settings can no longer be None so it's OK to unwrap
        let result = {
            try!(f(self.cache.borrow_mut().as_mut().unwrap()))
        };
        try!(self.write_settings());
        Ok(result)
    }
    pub fn maybe_upgrade_from_legacy(&self, multirust_dir: &Path) -> Result<()> {
        // Data locations
        let legacy_version_file = multirust_dir.join("version");
        if utils::is_file(&legacy_version_file) {
            fn split_override<T: FromStr>(s: &str, separator: char) -> Option<(T, T)> {
                s.find(separator).and_then(|index| {
                    match (T::from_str(&s[..index]), T::from_str(&s[index + 1..])) {
                        (Ok(l), Ok(r)) => Some((l, r)),
                        _ => None
                    }
                })
            }

            let override_db = multirust_dir.join("overrides");
            let default_file = multirust_dir.join("default");
            let telemetry_file = multirust_dir.join("telemetry-on");
            // Legacy upgrade
            try!(self.with_mut(|s| {
                s.version = try!(utils::read_file("version", &legacy_version_file))
                    .trim().to_owned();

                if utils::is_file(&default_file) {
                    s.default_toolchain = Some(try!(utils::read_file("default", &default_file))
                        .trim().to_owned());
                }
                if utils::is_file(&override_db) {
                    let overrides = try!(utils::read_file("overrides", &override_db));
                    for o in overrides.lines() {
                        if let Some((k, v)) = split_override(o, ';') {
                            s.overrides.insert(k, v);
                        }
                    }
                }
                if utils::is_file(&telemetry_file) {
                    s.telemetry = TelemetryMode::On;
                }
                Ok(())
            }));

            // Failure to delete these is not a fatal error
            let _ = utils::remove_file("version", &legacy_version_file);
            let _ = utils::remove_file("default", &default_file);
            let _ = utils::remove_file("overrides", &override_db);
            let _ = utils::remove_file("telemetry", &telemetry_file);
        }
        Ok(())
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum TelemetryMode {
    On,
    Off,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Settings {
    pub version: String,
    pub default_host_triple: Option<String>,
    pub default_toolchain: Option<String>,
    pub overrides: BTreeMap<String, String>,
    pub telemetry: TelemetryMode
}

impl Default for Settings {
    fn default() -> Self {
        Settings {
            version: DEFAULT_METADATA_VERSION.to_owned(),
            default_host_triple: None,
            default_toolchain: None,
            overrides: BTreeMap::new(),
            telemetry: TelemetryMode::Off
        }
    }
}

impl Settings {
    fn path_to_key(path: &Path, notify_handler: &Fn(Notification)) -> String {
        if path.exists() {
            utils::canonicalize_path(path, &|n| notify_handler(n.into())).display().to_string()
        } else {
            path.display().to_string()
        }
    }

    pub fn remove_override(&mut self, path: &Path, notify_handler: &Fn(Notification)) -> bool {
        let key = Self::path_to_key(path, notify_handler);
        self.overrides.remove(&key).is_some()
    }

    pub fn add_override(&mut self, path: &Path, toolchain: String, notify_handler: &Fn(Notification)) {
        let key = Self::path_to_key(path, notify_handler);
        notify_handler(Notification::SetOverrideToolchain(path, &toolchain));
        self.overrides.insert(key, toolchain);
    }

    pub fn find_override(&self, dir_unresolved: &Path, notify_handler: &Fn(Notification))
            -> Option<(String, PathBuf)> {
        let dir = utils::canonicalize_path(dir_unresolved, &|n| notify_handler(n.into()));
        let mut maybe_path = Some(&*dir);
        while let Some(path) = maybe_path {
            let key = Self::path_to_key(path, notify_handler);
            if let Some(toolchain) = self.overrides.get(&key) {
                return Some((toolchain.to_owned(), path.to_owned()));
            }
            maybe_path = path.parent();
        }
        None
    }

    pub fn parse(data: &str) -> Result<Self> {
        let mut parser = toml::Parser::new(data);
        let value = try!(parser.parse().ok_or_else(move || ErrorKind::ParsingSettings(parser.errors)));

        Self::from_toml(value, "")
    }
    pub fn stringify(self) -> String {
        toml::Value::Table(self.to_toml()).to_string()
    }

    pub fn from_toml(mut table: toml::Table, path: &str) -> Result<Self> {
        let version = try!(get_string(&mut table, "version", path));
        if !SUPPORTED_METADATA_VERSIONS.contains(&&*version) {
            return Err(ErrorKind::UnknownMetadataVersion(version).into());
        }
        Ok(Settings {
            version: version,
            default_host_triple: try!(get_opt_string(&mut table, "default_host_triple", path)),
            default_toolchain: try!(get_opt_string(&mut table, "default_toolchain", path)),
            overrides: try!(Self::table_to_overrides(&mut table, path)),
            telemetry: if try!(get_opt_bool(&mut table, "telemetry", path)).unwrap_or(false) {
                TelemetryMode::On
            } else {
                TelemetryMode::Off
            }
        })
    }
    pub fn to_toml(self) -> toml::Table {
        let mut result = toml::Table::new();

        result.insert("version".to_owned(),
                      toml::Value::String(self.version));

        if let Some(v) = self.default_host_triple {
            result.insert("default_host_triple".to_owned(), toml::Value::String(v));
        }

        if let Some(v) = self.default_toolchain {
            result.insert("default_toolchain".to_owned(), toml::Value::String(v));
        }

        let overrides = Self::overrides_to_table(self.overrides);
        result.insert("overrides".to_owned(), toml::Value::Table(overrides));

        let telemetry = self.telemetry == TelemetryMode::On;
        result.insert("telemetry".to_owned(), toml::Value::Boolean(telemetry));

        result
    }

    fn table_to_overrides(table: &mut toml::Table, path: &str) -> Result<BTreeMap<String, String>> {
        let mut result = BTreeMap::new();
        let pkg_table = try!(get_table(table, "overrides", path));

        for (k, v) in pkg_table {
            if let toml::Value::String(t) = v {
                result.insert(k, t);
            }
        }

        Ok(result)
    }

    fn overrides_to_table(overrides: BTreeMap<String, String>) -> toml::Table {
        let mut result = toml::Table::new();
        for (k, v) in overrides {
            result.insert(k, toml::Value::String(v));
        }
        result
    }
}
<|endoftext|>