<commit_before>extern crate presort;

use presort::PermutedVec;
use std::rc::Rc;
use std::cell::RefCell;

struct TreeNode<T> {
	//whether this node's data has changed
	dirty_val: bool,
	//whether some child node's data has changed
	dirty_child: bool,
	//number of children with unchanged decendent counts
	stable_children: usize,
	//parent and index in parent's child vec
	parent: Option<(Tree<T>, usize)>,
	//this node's data
    data: T,
    decendent_count: i32,
    children: Vec<Tree<T>>,
}

type Tree<T> = Rc<RefCell<TreeNode<T>>>;

trait IncTree<T: PartialEq + Clone> {
    fn new_node(data: T) -> Tree<T>;
	fn dirty_decendents(&self);
	fn dirty_parents(&self);
	fn mark_recount(&self, child_index: usize, new_nodes: i32);
	fn get_data(&self) -> T;
	fn set_data(&self, data: T);
	fn get_child(&self, child_num: usize) -> Tree<T>;
	fn set_child(&self, child_num: usize, child: Tree<T>);
	fn push_child(&self, child: Tree<T>);
	fn pop_child(&self) -> Option<Tree<T>>;
}

impl<T: PartialEq + Clone> IncTree<T> for Tree<T> {
	fn new_node(data: T) -> Tree<T>{
		Rc::new(RefCell::new(TreeNode {
			dirty_val: true,
			dirty_child: false,
			stable_children: 0,
			parent: None,
			data: data,
			decendent_count: 0,
			children: vec![]
		}))
	}

	//sets dirty flags, but leaves counts
	fn dirty_decendents(&self) {
		let mut tree = self.borrow_mut();
		tree.dirty_val = true;
		tree.dirty_child = true;
		for kid in &tree.children {
			kid.dirty_decendents();
		}
	}

	fn dirty_parents(&self){
		let mut parent = None;
		if let Some((ref p_tree,_)) = self.borrow().parent {
			parent = Some(p_tree.clone()); // Rc clone
		}
		if let Some(parent) = parent {
			parent.borrow_mut().dirty_child = true;
			parent.dirty_parents();
		}
	}

	//when a child changes number of decendents, we mark it in
	//this tree and bubble it up. This updates both
	//`decendent_count` and `stable_children`
	fn mark_recount(&self, child_index: usize, new_nodes: i32) {
		let mut tree = self.borrow_mut();
		tree.decendent_count += new_nodes;
		if tree.stable_children > child_index {
			tree.stable_children = child_index;
		}
		if let Some((ref parent, index)) = tree.parent {
			parent.mark_recount(index, new_nodes)
		}
	}

	fn get_data(&self) -> T {
		self.borrow().data.clone()
	}

	fn set_data(&self, data: T) {
		{
			let mut tree = self.borrow_mut();
			if tree.data == data {return}
			tree.data = data;
			tree.dirty_val = true;
		}
		self.dirty_parents();
	}

	fn get_child(&self, child_num: usize) -> Tree<T> {
		self.borrow().children[child_num].clone() //Rc clone
	}

	fn set_child(&self, child_num: usize, child: Tree<T>) {
		let mut tree = self.borrow_mut();
		//assume all new values are dirty
		child.dirty_decendents();
		child.borrow_mut().parent = Some((self.clone(), child_num)); //Rc clone
		child.dirty_parents();
		let mut nodes: i32 = 0;
		{
			//handle a change in the number of decendents
			let ref old_child = tree.children[child_num].borrow();
			if old_child.decendent_count != child.borrow().decendent_count {
				nodes -= old_child.decendent_count;
				nodes += child.borrow().decendent_count;
				child.borrow_mut().stable_children = 0;
				self.mark_recount(child_num, nodes);
			}
		}
		tree.children[child_num] = child;
	}

	fn push_child(&self, child: Tree<T>) {
		//assume all new values are dirty
		child.dirty_decendents();
		child.borrow_mut().parent = Some((self.clone(), self.borrow().children.len())); //Rc clone
		child.dirty_parents();
		let index;
		let nodes;
		{
			let mut tree = self.borrow_mut();
			nodes = 1 + child.borrow().decendent_count;
			index = tree.children.len();
			tree.children.push(child);
		}
		self.mark_recount(index, nodes);
	}

	fn pop_child(&self) -> Option<Tree<T>> {
		//assume all new values are dirty
		let child = self.borrow_mut().children.pop();
		let nodes = match child {
			None => 0,
			Some(ref c) => 1 + c.borrow().decendent_count,
		};
		let index = std::cmp::max(self.borrow().children.len(),0);
		self.mark_recount(index, -nodes);
		child
	}
}

fn dump<T: Clone>(tree: &Tree<T>, vec: &mut PermutedVec<T>) {
	let mut tree = tree.borrow_mut();
    vec.push(tree.data.clone());
    tree.dirty_val = false;
    for kid in &tree.children { dump(&kid, vec); }
    tree.dirty_child = false;
    tree.stable_children = tree.children.len();
}

fn update<T: Clone>(tree: &Tree<T>, start_index: usize, vec: &mut PermutedVec<T>) {
	let mut tree = tree.borrow_mut();
	let mut index = start_index;
	if tree.dirty_val {
		if vec.len() <= index {
			vec.push(tree.data.clone())
		} else {
			vec.set(index, tree.data.clone());
		}
		tree.dirty_val = false;
	}
	if !tree.dirty_child {return}
	index += 1;

	//all the children with unchanged decendent counts
	for counted_kid in 0..tree.stable_children{
		update(&tree.children[counted_kid], index, vec);
		index += 1 + tree.children[counted_kid].borrow_mut().decendent_count as usize;
	}
	if tree.stable_children < tree.children.len() {
		{
			//first changed child may have unchanged decendents
			let first_changed = &tree.children[tree.stable_children];
			update(&first_changed, index, vec);
			index += 1 + first_changed.borrow().decendent_count as usize;
		}
		//dump any additional children
		if (tree.stable_children + 1) < tree.children.len() {
			vec.truncate(index);
			for uncounted_kid in (tree.stable_children + 1)..tree.children.len() {
				dump(&tree.children[uncounted_kid], vec);
			}
			tree.stable_children = tree.children.len();
		}
	}
}

#[test]
fn test_tree() {
    let main_tree = Tree::new_node(37);
    let mut vec = PermutedVec::new();
    dump(&main_tree, &mut vec);
    assert_eq!(vec.sorted_iter().collect::<Vec<&usize>>(), vec![&37]);
}

#[test]
fn test_update() {
	println!("start first dump");
	let main_tree = Tree::new_node(37);
	main_tree.push_child(Tree::new_node(42));
	main_tree.push_child(Tree::new_node(20));
	main_tree.push_child(Tree::new_node(63));
	let mut vec = PermutedVec::new();
	dump(&main_tree, &mut vec);
	println!("finished first dump");
    assert_eq!(vec.sorted_iter().collect::<Vec<&usize>>(), vec![&20,&37,&42,&63]);

	println!("start first update");
    main_tree.get_child(1).set_data(25);
    update(&main_tree, 0, &mut vec);
	println!("finished first update");
    assert_eq!(vec.sorted_iter().collect::<Vec<&usize>>(), vec![&25,&37,&42,&63]);

	println!("start add branch");
    let branch = main_tree.get_child(2);
    branch.push_child(Tree::new_node(47));
    branch.push_child(Tree::new_node(53));
    branch.push_child(Tree::new_node(61));
    branch.push_child(Tree::new_node(57));
    update(&main_tree, 0, &mut vec);
	println!("finished add branch");
    assert_eq!(
    	vec.sorted_iter().collect::<Vec<&usize>>(),
    	vec![&25,&37,&42,&47,&53,&57,&61,&63]
    );

	println!("start update branch");
    branch.get_child(2).set_data(77);
    update(&main_tree, 0, &mut vec);
	println!("finished update branch");
    assert_eq!(
    	vec.sorted_iter().collect::<Vec<&usize>>(),
    	vec![&25,&37,&42,&47,&53,&57,&63,&77]
    );

    println!("start early insertion");
    let branch = main_tree.get_child(1);
    branch.push_child(Tree::new_node(1));
    update(&main_tree, 0, &mut vec);
    println!("finished early insertion");
    assert_eq!(
    	vec.sorted_iter().collect::<Vec<&usize>>(),
    	vec![&1,&25,&37,&42,&47,&53,&57,&63,&77]
    );

    println!("start deep add");
    let branch = main_tree.get_child(2).get_child(2);
    let new_branch = Tree::new_node(100);
    new_branch.push_child(Tree::new_node(101));
    branch.push_child(new_branch);
    update(&main_tree, 0, &mut vec);
    println!("finished deep add");
    assert_eq!(
    	vec.sorted_iter().collect::<Vec<&usize>>(),
    	vec![&1,&25,&37,&42,&47,&53,&57,&63,&77,&100,&101]
    );

    println!("start deep edit");
    let branch = branch.get_child(0).get_child(0);
    branch.set_data(105);
    update(&main_tree, 0, &mut vec);
    println!("finished deep edit");
    assert_eq!(
    	vec.sorted_iter().collect::<Vec<&usize>>(),
    	vec![&1,&25,&37,&42,&47,&53,&57,&63,&77,&100,&105]
    );

    println!("start pop branch");
    let branch = main_tree.get_child(2).get_child(2);
    branch.pop_child();
    update(&main_tree, 0, &mut vec);
    println!("finished pop branch");
    assert_eq!(
    	vec.sorted_iter().collect::<Vec<&usize>>(),
    	vec![&1,&25,&37,&42,&47,&53,&57,&63,&77]
    );

}
<commit_msg>Renamed dirty_child to dirty_descendant.<commit_after>extern crate presort;

use presort::PermutedVec;
use std::rc::Rc;
use std::cell::RefCell;

struct TreeNode<T> {
	//whether this node's data has changed
	dirty_val: bool,
	//whether some descendant is dirty
	dirty_descendant: bool,
	//number of children with unchanged decendent counts
	stable_children: usize,
	//parent and index in parent's child vec
	parent: Option<(Tree<T>, usize)>,
	//this node's data
    data: T,
    decendent_count: i32,
    children: Vec<Tree<T>>,
}

type Tree<T> = Rc<RefCell<TreeNode<T>>>;

trait IncTree<T: PartialEq + Clone> {
    fn new_node(data: T) -> Tree<T>;
	fn dirty_decendents(&self);
	fn dirty_parents(&self);
	fn mark_recount(&self, child_index: usize, new_nodes: i32);
	fn get_data(&self) -> T;
	fn set_data(&self, data: T);
	fn get_child(&self, child_num: usize) -> Tree<T>;
	fn set_child(&self, child_num: usize, child: Tree<T>);
	fn push_child(&self, child: Tree<T>);
	fn pop_child(&self) -> Option<Tree<T>>;
}

impl<T: PartialEq + Clone> IncTree<T> for Tree<T> {
	fn new_node(data: T) -> Tree<T>{
		Rc::new(RefCell::new(TreeNode {
			dirty_val: true,
			dirty_descendant: false,
			stable_children: 0,
			parent: None,
			data: data,
			decendent_count: 0,
			children: vec![]
		}))
	}

	//sets dirty flags, but leaves counts
	fn dirty_decendents(&self) {
		let mut tree = self.borrow_mut();
		tree.dirty_val = true;
		tree.dirty_descendant = true;
		for kid in &tree.children {
			kid.dirty_decendents();
		}
	}

	fn dirty_parents(&self){
		let mut parent = None;
		if let Some((ref p_tree,_)) = self.borrow().parent {
			parent = Some(p_tree.clone()); // Rc clone
		}
		if let Some(parent) = parent {
			parent.borrow_mut().dirty_descendant = true;
			parent.dirty_parents();
		}
	}

	//when a child changes number of decendents, we mark it in
	//this tree and bubble it up. This updates both
	//`decendent_count` and `stable_children`
	fn mark_recount(&self, child_index: usize, new_nodes: i32) {
		let mut tree = self.borrow_mut();
		tree.decendent_count += new_nodes;
		if tree.stable_children > child_index {
			tree.stable_children = child_index;
		}
		if let Some((ref parent, index)) = tree.parent {
			parent.mark_recount(index, new_nodes)
		}
	}

	fn get_data(&self) -> T {
		self.borrow().data.clone()
	}

	fn set_data(&self, data: T) {
		{
			let mut tree = self.borrow_mut();
			if tree.data == data {return}
			tree.data = data;
			tree.dirty_val = true;
		}
		self.dirty_parents();
	}

	fn get_child(&self, child_num: usize) -> Tree<T> {
		self.borrow().children[child_num].clone() //Rc clone
	}

	fn set_child(&self, child_num: usize, child: Tree<T>) {
		let mut tree = self.borrow_mut();
		//assume all new values are dirty
		child.dirty_decendents();
		child.borrow_mut().parent = Some((self.clone(), child_num)); //Rc clone
		child.dirty_parents();
		let mut nodes: i32 = 0;
		{
			//handle a change in the number of decendents
			let ref old_child = tree.children[child_num].borrow();
			if old_child.decendent_count != child.borrow().decendent_count {
				nodes -= old_child.decendent_count;
				nodes += child.borrow().decendent_count;
				child.borrow_mut().stable_children = 0;
				self.mark_recount(child_num, nodes);
			}
		}
		tree.children[child_num] = child;
	}

	fn push_child(&self, child: Tree<T>) {
		//assume all new values are dirty
		child.dirty_decendents();
		child.borrow_mut().parent = Some((self.clone(), self.borrow().children.len())); //Rc clone
		child.dirty_parents();
		let index;
		let nodes;
		{
			let mut tree = self.borrow_mut();
			nodes = 1 + child.borrow().decendent_count;
			index = tree.children.len();
			tree.children.push(child);
		}
		self.mark_recount(index, nodes);
	}

	fn pop_child(&self) -> Option<Tree<T>> {
		//assume all new values are dirty
		let child = self.borrow_mut().children.pop();
		let nodes = match child {
			None => 0,
			Some(ref c) => 1 + c.borrow().decendent_count,
		};
		let index = std::cmp::max(self.borrow().children.len(),0);
		self.mark_recount(index, -nodes);
		child
	}
}

fn dump<T: Clone>(tree: &Tree<T>, vec: &mut PermutedVec<T>) {
	let mut tree = tree.borrow_mut();
    vec.push(tree.data.clone());
    tree.dirty_val = false;
    for kid in &tree.children { dump(&kid, vec); }
    tree.dirty_descendant = false;
    tree.stable_children = tree.children.len();
}

fn update<T: Clone>(tree: &Tree<T>, start_index: usize, vec: &mut PermutedVec<T>) {
	let mut tree = tree.borrow_mut();
	let mut index = start_index;
	if tree.dirty_val {
		if vec.len() <= index {
			vec.push(tree.data.clone())
		} else {
			vec.set(index, tree.data.clone());
		}
		tree.dirty_val = false;
	}
	if !tree.dirty_descendant {return}
	index += 1;

	//all the children with unchanged decendent counts
	for counted_kid in 0..tree.stable_children{
		update(&tree.children[counted_kid], index, vec);
		index += 1 + tree.children[counted_kid].borrow_mut().decendent_count as usize;
	}
	if tree.stable_children < tree.children.len() {
		{
			//first changed child may have unchanged decendents
			let first_changed = &tree.children[tree.stable_children];
			update(&first_changed, index, vec);
			index += 1 + first_changed.borrow().decendent_count as usize;
		}
		//dump any additional children
		if (tree.stable_children + 1) < tree.children.len() {
			vec.truncate(index);
			for uncounted_kid in (tree.stable_children + 1)..tree.children.len() {
				dump(&tree.children[uncounted_kid], vec);
			}
			tree.stable_children = tree.children.len();
		}
	}
}

#[test]
fn test_tree() {
    let main_tree = Tree::new_node(37);
    let mut vec = PermutedVec::new();
    dump(&main_tree, &mut vec);
    assert_eq!(vec.sorted_iter().collect::<Vec<&usize>>(), vec![&37]);
}

#[test]
fn test_update() {
	println!("start first dump");
	let main_tree = Tree::new_node(37);
	main_tree.push_child(Tree::new_node(42));
	main_tree.push_child(Tree::new_node(20));
	main_tree.push_child(Tree::new_node(63));
	let mut vec = PermutedVec::new();
	dump(&main_tree, &mut vec);
	println!("finished first dump");
    assert_eq!(vec.sorted_iter().collect::<Vec<&usize>>(), vec![&20,&37,&42,&63]);

	println!("start first update");
    main_tree.get_child(1).set_data(25);
    update(&main_tree, 0, &mut vec);
	println!("finished first update");
    assert_eq!(vec.sorted_iter().collect::<Vec<&usize>>(), vec![&25,&37,&42,&63]);

	println!("start add branch");
    let branch = main_tree.get_child(2);
    branch.push_child(Tree::new_node(47));
    branch.push_child(Tree::new_node(53));
    branch.push_child(Tree::new_node(61));
    branch.push_child(Tree::new_node(57));
    update(&main_tree, 0, &mut vec);
	println!("finished add branch");
    assert_eq!(
    	vec.sorted_iter().collect::<Vec<&usize>>(),
    	vec![&25,&37,&42,&47,&53,&57,&61,&63]
    );

	println!("start update branch");
    branch.get_child(2).set_data(77);
    update(&main_tree, 0, &mut vec);
	println!("finished update branch");
    assert_eq!(
    	vec.sorted_iter().collect::<Vec<&usize>>(),
    	vec![&25,&37,&42,&47,&53,&57,&63,&77]
    );

    println!("start early insertion");
    let branch = main_tree.get_child(1);
    branch.push_child(Tree::new_node(1));
    update(&main_tree, 0, &mut vec);
    println!("finished early insertion");
    assert_eq!(
    	vec.sorted_iter().collect::<Vec<&usize>>(),
    	vec![&1,&25,&37,&42,&47,&53,&57,&63,&77]
    );

    println!("start deep add");
    let branch = main_tree.get_child(2).get_child(2);
    let new_branch = Tree::new_node(100);
    new_branch.push_child(Tree::new_node(101));
    branch.push_child(new_branch);
    update(&main_tree, 0, &mut vec);
    println!("finished deep add");
    assert_eq!(
    	vec.sorted_iter().collect::<Vec<&usize>>(),
    	vec![&1,&25,&37,&42,&47,&53,&57,&63,&77,&100,&101]
    );

    println!("start deep edit");
    let branch = branch.get_child(0).get_child(0);
    branch.set_data(105);
    update(&main_tree, 0, &mut vec);
    println!("finished deep edit");
    assert_eq!(
    	vec.sorted_iter().collect::<Vec<&usize>>(),
    	vec![&1,&25,&37,&42,&47,&53,&57,&63,&77,&100,&105]
    );

    println!("start pop branch");
    let branch = main_tree.get_child(2).get_child(2);
    branch.pop_child();
    update(&main_tree, 0, &mut vec);
    println!("finished pop branch");
    assert_eq!(
    	vec.sorted_iter().collect::<Vec<&usize>>(),
    	vec![&1,&25,&37,&42,&47,&53,&57,&63,&77]
    );

}
<|endoftext|>


<commit_before>extern crate chattium_oxide_lib as cho;  // Chang
extern crate rand;
extern crate time;

use time::Tm;
use rand::Rng;
use std::net::Ipv4Addr;

fn random_ip<Rand: Rng>(rng: &mut Rand) -> (Ipv4Addr, u16) {
	(Ipv4Addr::new(rng.gen(), rng.gen(), rng.gen(), rng.gen()), rng.gen())
}

fn random_name<Rand: Rng>(rng: &mut Rand) -> String {
	rng.gen_ascii_chars().take(10).collect()
}

fn random_text<Rand: Rng>(rng: &mut Rand) -> String {
	rng.gen_ascii_chars().take(100).collect()
}

fn random_time<Rand: Rng>(rng: &mut Rand) -> Tm {
	use time::{at_utc, Timespec};

	at_utc(Timespec::new(rng.gen_range(1420070400 /*1 Jan. 2015*/, 1893456000 /*1. Jan 2030*/), rng.gen_range(0, 1000000000)))
}

#[cfg(test)]
mod user {
	use random_ip;
	use random_name;
	use rand;
	use cho::*;

	#[test]
	fn self_eq_self() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
			assert_eq!(user, user);
		}
	}

	#[test]
	fn equal_because_of_different_names_same_ips() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let ip = random_ip(&mut rng);
			let user_1 = ChatUser::get(random_name(&mut rng), ip);
			let user_2 = ChatUser::get(random_name(&mut rng), ip);
			assert_eq!(user_1, user_2);
		}
	}

	#[test]
	fn unequal_because_of_different_ips_same_names() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let user_1 = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
			let user_2 = ChatUser::get(user_1.name.clone(), random_ip(&mut rng));
			assert!(user_1 != user_2);
		}
	}

	#[test]
	fn name_of_instance_from_get_is_equal_to_passed_name() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let name = random_name(&mut rng);
			let user = ChatUser::get(name.clone(), "0.0.0.0:0");
			assert_eq!(user.name, name);
		}
	}

	#[test]
	fn cloner_eq_clonee() {
		let mut rng = rand::thread_rng();

		let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
		let clone = user.clone();
		assert_eq!(user, clone);
		assert_eq!(user.name, clone.name);
	}

	mod j_son {
		use random_ip;
		use random_name;
		use rand;
		use cho::*;
		use cho::json::*;

		#[test]
		fn full_transserializes_properly() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
				let trans = ChatUser::from_json(user.to_json()).expect("Full transserialization");
				assert_eq!(user, trans);
				assert_eq!(user.name, trans.name);
			}
		}

		#[test]
		fn ipless_transserializes_properly() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let user = ChatUser::me(random_name(&mut rng));
				let trans = ChatUser::from_json(user.to_json()).expect("IP-less transserialization");
				assert_eq!(user, trans);
				assert_eq!(user.name, trans.name);
			}
		}
		#[test]
		fn full_transserializes_properly_through_string() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
				let user_s = user.to_json_string().expect("Full serialization to string");
				let trans = ChatUser::from_json_string(&user_s).expect("Full deserialization from string");
				assert_eq!(user, trans);
				assert_eq!(user.name, trans.name);
			}
		}

		#[test]
		fn ipless_transserializes_properly_through_string() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let user = ChatUser::me(random_name(&mut rng));
				let user_s = user.to_json_string().expect("IP-less serialization to string");
				let trans = ChatUser::from_json_string(&user_s).expect("IP-less deserialization from string");
				assert_eq!(user, trans);
				assert_eq!(user.name, trans.name);
			}
		}

		#[test]
		//#[should_fail]  // The attribute `should_fail` is currently unknown to the compiler and may have meaning added to it in the future
		fn deserialization_from_malformed_fails() {
			ChatUser::from_json_string(&"{\"user\": \"you\"}".to_string()).unwrap_err();
		}
	}
}

#[cfg(test)]
mod message {
	use random_ip;
	use random_name;
	use random_text;
	use rand;
	use cho::*;
	use std::time::Duration;
	use std::thread::sleep;

	#[test]
	fn self_eq_self() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), random_text(&mut rng));
			assert_eq!(message, message);
		}
	}

	#[test]
	fn new_neq_new_time() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
			let text = random_text(&mut rng);
			let message_1 = ChatMessage::new(user.clone(), text.clone());
			sleep(Duration::new(0, 1));
			let message_2 = ChatMessage::new(user.clone(), text.clone());
			assert!(message_1.time_posted != message_2.time_posted);
		}
	}

	#[test]
	fn user_of_instance_from_new_is_equal_to_passed_user() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let sender = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
			let message = ChatMessage::new(sender.clone(), random_text(&mut rng));
			assert_eq!(message.sender, sender);
		}
	}

	#[test]
	fn content_of_instance_from_new_is_equal_to_passed_content() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let value = random_text(&mut rng);
			let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), value.clone());
			assert_eq!(message.value, value);
		}
	}

	#[test]
	fn cloner_eq_clonee() {
		let mut rng = rand::thread_rng();

		let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), random_text(&mut rng));
		let clone = message.clone();
		assert_eq!(message, clone);
	}

	mod j_son {
		use random_ip;
		use random_name;
		use random_text;
		use rand;
		use cho::*;
		use cho::json::*;

		#[test]
		fn full_transserializes_properly() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), random_text(&mut rng));
				let trans = ChatMessage::from_json(message.to_json()).expect("Full transserialization via ChatMessage");
				assert_eq!(message, trans);
			}
		}

		#[test]
		fn ipless_transserializes_properly() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let message = ChatMessage::new(ChatUser::me(random_name(&mut rng)), random_text(&mut rng));;
				let trans = ChatMessage::from_json(message.to_json()).expect("IP-less transserialization via ChatMessage");
				assert_eq!(message, trans);
			}
		}
		#[test]
		fn full_transserializes_properly_through_string() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), random_text(&mut rng));
				let message_s = message.to_json_string().expect("Full serialization to string via ChatMessage");
				let trans = ChatMessage::from_json_string(&message_s).expect("Full deserialization from string via ChatMessage");
				assert_eq!(message, trans);
			}
		}

		#[test]
		fn ipless_transserializes_properly_through_string() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let message = ChatMessage::new(ChatUser::me(random_name(&mut rng)), random_text(&mut rng));;
				let message_s = message.to_json_string().expect("IP-less serialization to string via ChatMessage");
				let trans = ChatMessage::from_json_string(&message_s).expect("IP-less deserialization from string via ChatMessage");
				assert_eq!(message, trans);
			}
		}

		#[test]
		//#[should_fail]  // The attribute `should_fail` is currently unknown to the compiler and may have meaning added to it in the future
		fn deserialization_from_malformed_fails() {
			ChatMessage::from_json_string(&"{\"user\": \"you\"}".to_string()).unwrap_err();
		}
	}
}

#[cfg(test)]
mod json_impl {
	use rand;
	use time::Tm;
	use random_time;
	use cho::json::*;

	#[test]
	fn time_transserializes_properly() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let time = random_time(&mut rng);
			let time_s = time.to_json_string().expect("Serialization to string via time::Tm");
			let trans = Tm::from_json_string(&time_s).expect("Deserialization from string via time::Tm");
			assert_eq!(time, trans);
		}
	}
}
<commit_msg>Add primitive type transserialization tests<commit_after>extern crate chattium_oxide_lib as cho;  // Chang
extern crate rand;
extern crate time;

use time::Tm;
use rand::Rng;
use std::net::Ipv4Addr;

fn random_ip<Rand: Rng>(rng: &mut Rand) -> (Ipv4Addr, u16) {
	(Ipv4Addr::new(rng.gen(), rng.gen(), rng.gen(), rng.gen()), rng.gen())
}

fn random_name<Rand: Rng>(rng: &mut Rand) -> String {
	rng.gen_ascii_chars().take(10).collect()
}

fn random_text<Rand: Rng>(rng: &mut Rand) -> String {
	rng.gen_ascii_chars().take(100).collect()
}

fn random_time<Rand: Rng>(rng: &mut Rand) -> Tm {
	use time::{at_utc, Timespec};

	at_utc(Timespec::new(rng.gen_range(1420070400 /*1 Jan. 2015*/, 1893456000 /*1. Jan 2030*/), rng.gen_range(0, 1000000000)))
}

#[cfg(test)]
mod user {
	use random_ip;
	use random_name;
	use rand;
	use cho::*;

	#[test]
	fn self_eq_self() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
			assert_eq!(user, user);
		}
	}

	#[test]
	fn equal_because_of_different_names_same_ips() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let ip = random_ip(&mut rng);
			let user_1 = ChatUser::get(random_name(&mut rng), ip);
			let user_2 = ChatUser::get(random_name(&mut rng), ip);
			assert_eq!(user_1, user_2);
		}
	}

	#[test]
	fn unequal_because_of_different_ips_same_names() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let user_1 = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
			let user_2 = ChatUser::get(user_1.name.clone(), random_ip(&mut rng));
			assert!(user_1 != user_2);
		}
	}

	#[test]
	fn name_of_instance_from_get_is_equal_to_passed_name() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let name = random_name(&mut rng);
			let user = ChatUser::get(name.clone(), "0.0.0.0:0");
			assert_eq!(user.name, name);
		}
	}

	#[test]
	fn cloner_eq_clonee() {
		let mut rng = rand::thread_rng();

		let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
		let clone = user.clone();
		assert_eq!(user, clone);
		assert_eq!(user.name, clone.name);
	}

	mod j_son {
		use random_ip;
		use random_name;
		use rand;
		use cho::*;
		use cho::json::*;

		#[test]
		fn full_transserializes_properly() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
				let trans = ChatUser::from_json(user.to_json()).expect("Full transserialization");
				assert_eq!(user, trans);
				assert_eq!(user.name, trans.name);
			}
		}

		#[test]
		fn ipless_transserializes_properly() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let user = ChatUser::me(random_name(&mut rng));
				let trans = ChatUser::from_json(user.to_json()).expect("IP-less transserialization");
				assert_eq!(user, trans);
				assert_eq!(user.name, trans.name);
			}
		}
		#[test]
		fn full_transserializes_properly_through_string() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
				let user_s = user.to_json_string().expect("Full serialization to string");
				let trans = ChatUser::from_json_string(&user_s).expect("Full deserialization from string");
				assert_eq!(user, trans);
				assert_eq!(user.name, trans.name);
			}
		}

		#[test]
		fn ipless_transserializes_properly_through_string() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let user = ChatUser::me(random_name(&mut rng));
				let user_s = user.to_json_string().expect("IP-less serialization to string");
				let trans = ChatUser::from_json_string(&user_s).expect("IP-less deserialization from string");
				assert_eq!(user, trans);
				assert_eq!(user.name, trans.name);
			}
		}

		#[test]
		//#[should_fail]  // The attribute `should_fail` is currently unknown to the compiler and may have meaning added to it in the future
		fn deserialization_from_malformed_fails() {
			ChatUser::from_json_string(&"{\"user\": \"you\"}".to_string()).unwrap_err();
		}
	}
}

#[cfg(test)]
mod message {
	use random_ip;
	use random_name;
	use random_text;
	use rand;
	use cho::*;
	use std::time::Duration;
	use std::thread::sleep;

	#[test]
	fn self_eq_self() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), random_text(&mut rng));
			assert_eq!(message, message);
		}
	}

	#[test]
	fn new_neq_new_time() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let user = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
			let text = random_text(&mut rng);
			let message_1 = ChatMessage::new(user.clone(), text.clone());
			sleep(Duration::new(0, 1));
			let message_2 = ChatMessage::new(user.clone(), text.clone());
			assert!(message_1.time_posted != message_2.time_posted);
		}
	}

	#[test]
	fn user_of_instance_from_new_is_equal_to_passed_user() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let sender = ChatUser::get(random_name(&mut rng), random_ip(&mut rng));
			let message = ChatMessage::new(sender.clone(), random_text(&mut rng));
			assert_eq!(message.sender, sender);
		}
	}

	#[test]
	fn content_of_instance_from_new_is_equal_to_passed_content() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let value = random_text(&mut rng);
			let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), value.clone());
			assert_eq!(message.value, value);
		}
	}

	#[test]
	fn cloner_eq_clonee() {
		let mut rng = rand::thread_rng();

		let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), random_text(&mut rng));
		let clone = message.clone();
		assert_eq!(message, clone);
	}

	mod j_son {
		use random_ip;
		use random_name;
		use random_text;
		use rand;
		use cho::*;
		use cho::json::*;

		#[test]
		fn full_transserializes_properly() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), random_text(&mut rng));
				let trans = ChatMessage::from_json(message.to_json()).expect("Full transserialization via ChatMessage");
				assert_eq!(message, trans);
			}
		}

		#[test]
		fn ipless_transserializes_properly() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let message = ChatMessage::new(ChatUser::me(random_name(&mut rng)), random_text(&mut rng));;
				let trans = ChatMessage::from_json(message.to_json()).expect("IP-less transserialization via ChatMessage");
				assert_eq!(message, trans);
			}
		}
		#[test]
		fn full_transserializes_properly_through_string() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let message = ChatMessage::new(ChatUser::get(random_name(&mut rng), random_ip(&mut rng)), random_text(&mut rng));
				let message_s = message.to_json_string().expect("Full serialization to string via ChatMessage");
				let trans = ChatMessage::from_json_string(&message_s).expect("Full deserialization from string via ChatMessage");
				assert_eq!(message, trans);
			}
		}

		#[test]
		fn ipless_transserializes_properly_through_string() {
			let mut rng = rand::thread_rng();
			let times = if cfg!(feature = "ci") {100000} else {1000};

			for _ in 1..times {
				let message = ChatMessage::new(ChatUser::me(random_name(&mut rng)), random_text(&mut rng));;
				let message_s = message.to_json_string().expect("IP-less serialization to string via ChatMessage");
				let trans = ChatMessage::from_json_string(&message_s).expect("IP-less deserialization from string via ChatMessage");
				assert_eq!(message, trans);
			}
		}

		#[test]
		//#[should_fail]  // The attribute `should_fail` is currently unknown to the compiler and may have meaning added to it in the future
		fn deserialization_from_malformed_fails() {
			ChatMessage::from_json_string(&"{\"user\": \"you\"}".to_string()).unwrap_err();
		}
	}
}

#[cfg(test)]
mod json_impl {
	use rand::{self, Rng};
	use time::Tm;
	use random_time;
	use cho::json::*;
	use std::{f32, f64};

	macro_rules! primitive_test {
		($t:ty, $s:expr, $name:ident, $cmp:expr) => {
			#[test]
			fn $name() {
				let mut rng = rand::thread_rng();
				let times = if cfg!(feature = "ci") {100000} else {1000};

				let ser_msg = &*&("Serialization to string via ".to_string() + $s);
				let des_msg = &*&("Deserialization from string via ".to_string() + $s);
				for _ in 1..times {
					let num: $t = rng.gen();
					let num_s = num.to_json_string().expect(ser_msg);
					let trans = FromJsonnable::from_json_string(&num_s).expect(des_msg);
					println!("{:?} = {:?}", num, trans);
					$cmp(num, trans);
				}
			}
		};
	}

	#[test]
	fn time_transserializes_properly() {
		let mut rng = rand::thread_rng();
		let times = if cfg!(feature = "ci") {100000} else {1000};

		for _ in 1..times {
			let time = random_time(&mut rng);
			let time_s = time.to_json_string().expect("Serialization to string via time::Tm");
			let trans = Tm::from_json_string(&time_s).expect("Deserialization from string via time::Tm");
			assert_eq!(time, trans);
		}
	}

	primitive_test!(i8,  "i8",  i8_transserializes_properly,  |n, t| assert_eq!(n, t));
	primitive_test!(i16, "i16", i16_transserializes_properly, |n, t| assert_eq!(n, t));
	primitive_test!(i32, "i32", i32_transserializes_properly, |n, t| assert_eq!(n, t));
	primitive_test!(i64, "i64", i64_transserializes_properly, |n, t| assert_eq!(n, t));

	primitive_test!(u8,  "u8",  u8_transserializes_properly,  |n, t| assert_eq!(n, t));
	primitive_test!(u16, "u16", u16_transserializes_properly, |n, t| assert_eq!(n, t));
	primitive_test!(u32, "u32", u32_transserializes_properly, |n, t| assert_eq!(n, t));
	primitive_test!(u64, "u64", u64_transserializes_properly, |n, t| assert_eq!(n, t));

	primitive_test!(f32, "f32", f32_transserializes_properly, |n: f32, t: f32| assert!((n - t).abs() < f32::EPSILON * 10f32));
	primitive_test!(f64, "f64", f64_transserializes_properly, |n: f64, t: f64| assert!((n - t).abs() < f64::EPSILON * 10f64));
}
<|endoftext|>


<commit_before>use engine::Game;
use gui::screens::{self, Screen, ScreenChange};
use gui::{Console, Colors, Key};
use gui::chars;
use util::units::{Direction, Point, Rectangle, Size};

#[allow(missing_copy_implementations)]
pub struct GameScreen {
    map_frame: Rectangle,
    map_view: Point,
    info_frame: Rectangle,
    message_frame: Rectangle,
}

impl GameScreen {
    pub fn new() -> Box<Screen> {
        Box::new(
            GameScreen {
                map_frame: Rectangle::new(Point::new(16, 1), Size::new(63, 38)),
                map_view: Point::new(0, 0),
                info_frame: Rectangle::new(Point::new(1, 1), Size::new(13, 48)),
                message_frame: Rectangle::new(Point::new(16, 41), Size::new(63, 8)),
            }
        )
    }
}

impl Screen for GameScreen {

    #[allow(unused)]
    fn input(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        if let Some(key) = console.check_for_keypress() {
            match key {
                Key::Up => {
                    game.world.walk(Direction::Up);
                },
                Key::Down => {
                    game.world.walk(Direction::Down);
                },
                Key::Left => {
                    game.world.walk(Direction::Left);
                },
                Key::Right => {
                    game.world.walk(Direction::Right);
                },
                Key::Escape => {
                    return Some(ScreenChange::AddScreen(screens::PauseScreen::new()));
                },
                _ => {}
            }
        }

        None
    }

    #[allow(unused)]
    fn update(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        None
    }

    #[allow(unused)]
    fn render(&mut self, game: &mut Game, console: &mut Console) {
        self.draw_borders(game, console);
        self.draw_map(game, console);
        self.draw_player(game, console);
    }
}

impl GameScreen {

    #[allow(unused)]
    fn draw_borders(&self, game: &mut Game, console: &mut Console) {
        self.draw_box(console, self.map_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.map_frame.move_dir(Point::new(0, -1)).location(), "Map");

        self.draw_box(console, self.info_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.info_frame.move_dir(Point::new(0, -1)).location(), "Info");

        self.draw_box(console, self.message_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.message_frame.move_dir(Point::new(0, -1)).location(), "Messages");
    }

    fn draw_box(&self, console: &mut Console, rect: Rectangle) {
        console.put_plain(rect.location() + Point::new(0, 0), chars::NW);
        console.put_plain(rect.location() + Point::new(rect.width(), 0), chars::NE);
        console.put_plain(rect.location() + Point::new(0, rect.height()), chars::SW);
        console.put_plain(rect.location() + Point::new(rect.width(), rect.height()), chars::SE);

        for x in 1..rect.width() {
            console.put_plain(rect.location() + Point::new(x, 0), chars::HLINE);
            console.put_plain(rect.location() + Point::new(x, rect.height()), chars::HLINE);
        }

        for y in 1..rect.height() {
            console.put_plain(rect.location() + Point::new(0, y), chars::VLINE);
            console.put_plain(rect.location() + Point::new(rect.width(), y), chars::VLINE);
        }
    }

    #[allow(unused)]
    fn draw_map(&self, game: &mut Game, console: &mut Console) {
        let map = &game.world.map;

        for (y, line) in map.tiles[self.map_view.y as usize .. self.map_view.y as usize + self.map_frame.height() as usize].iter().enumerate() {
            for (x, cell) in line[self.map_view.x as usize .. self.map_view.x as usize + self.map_frame.width() as usize].iter().enumerate() {
                console.put(self.map_frame.location() + Point::new(x as i32, y as i32), ' ', Colors::white, cell.b_color());
            }
        }
    }

    #[allow(unused)]
    fn draw_player(&mut self, game: &mut Game, console: &mut Console) {
        let repr = game.world.player.repr;
        let pos = game.world.player.pos;

        let adjusted_pos = pos + self.map_frame.location() - self.map_view;

        if adjusted_pos.x >= self.map_frame.location().x + self.map_frame.width() - 10 {
            if self.view_can_move_right(game) {
                self.map_view = self.map_view.right(1);
            }
        }

        if adjusted_pos.y >= self.map_frame.location().y + self.map_frame.height() - 5 {
            if self.view_can_move_down(game) {
                self.map_view = self.map_view.down(1);
            }
        }

        if adjusted_pos.y <= self.map_frame.location().y + 5 {
            if self.view_can_move_up(game) {
                self.map_view = self.map_view.up(1);
            }
        }

        if adjusted_pos.x <= self.map_frame.location().x + 10 {
            if self.view_can_move_left(game) {
                self.map_view = self.map_view.left(1);
            }
        }

        if adjusted_pos.x >= self.map_frame.location().x && adjusted_pos.y >= self.map_frame.location().y {
            console.put_plain(self.map_frame.location() - self.map_view + pos, repr);
        }
    }

    #[allow(unused)]
    fn view_can_move_up(&self, game: &Game) -> bool {
        self.map_view.y  > 0
    }

    #[allow(unused)]
    fn view_can_move_down(&self, game: &Game) -> bool {
        self.map_view.y + self.map_frame.height() < game.world.map.height()
    }

    #[allow(unused)]
    fn view_can_move_left(&self, game: &Game) -> bool {
        self.map_view.x > 0
    }

    #[allow(unused)]
    fn view_can_move_right(&self, game: &Game) -> bool {
        self.map_view.x + self.map_frame.width() < game.world.map.width()
    }

}
<commit_msg>Remove a lot of 'as usize' casting in map drawing<commit_after>use engine::Game;
use gui::screens::{self, Screen, ScreenChange};
use gui::{Console, Colors, Key};
use gui::chars;
use util::units::{AsTuple, Direction, Point, Rectangle, Size};

#[allow(missing_copy_implementations)]
pub struct GameScreen {
    map_frame: Rectangle,
    map_view: Point,
    info_frame: Rectangle,
    message_frame: Rectangle,
}

impl GameScreen {
    pub fn new() -> Box<Screen> {
        Box::new(
            GameScreen {
                map_frame: Rectangle::new(Point::new(16, 1), Size::new(63, 38)),
                map_view: Point::new(0, 0),
                info_frame: Rectangle::new(Point::new(1, 1), Size::new(13, 48)),
                message_frame: Rectangle::new(Point::new(16, 41), Size::new(63, 8)),
            }
        )
    }
}

impl Screen for GameScreen {

    #[allow(unused)]
    fn input(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        if let Some(key) = console.check_for_keypress() {
            match key {
                Key::Up => {
                    game.world.walk(Direction::Up);
                },
                Key::Down => {
                    game.world.walk(Direction::Down);
                },
                Key::Left => {
                    game.world.walk(Direction::Left);
                },
                Key::Right => {
                    game.world.walk(Direction::Right);
                },
                Key::Escape => {
                    return Some(ScreenChange::AddScreen(screens::PauseScreen::new()));
                },
                _ => {}
            }
        }

        None
    }

    #[allow(unused)]
    fn update(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        None
    }

    #[allow(unused)]
    fn render(&mut self, game: &mut Game, console: &mut Console) {
        self.draw_borders(game, console);
        self.draw_map(game, console);
        self.draw_player(game, console);
    }
}

impl GameScreen {

    #[allow(unused)]
    fn draw_borders(&self, game: &mut Game, console: &mut Console) {
        self.draw_box(console, self.map_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.map_frame.move_dir(Point::new(0, -1)).location(), "Map");

        self.draw_box(console, self.info_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.info_frame.move_dir(Point::new(0, -1)).location(), "Info");

        self.draw_box(console, self.message_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.message_frame.move_dir(Point::new(0, -1)).location(), "Messages");
    }

    fn draw_box(&self, console: &mut Console, rect: Rectangle) {
        console.put_plain(rect.location() + Point::new(0, 0), chars::NW);
        console.put_plain(rect.location() + Point::new(rect.width(), 0), chars::NE);
        console.put_plain(rect.location() + Point::new(0, rect.height()), chars::SW);
        console.put_plain(rect.location() + Point::new(rect.width(), rect.height()), chars::SE);

        for x in 1..rect.width() {
            console.put_plain(rect.location() + Point::new(x, 0), chars::HLINE);
            console.put_plain(rect.location() + Point::new(x, rect.height()), chars::HLINE);
        }

        for y in 1..rect.height() {
            console.put_plain(rect.location() + Point::new(0, y), chars::VLINE);
            console.put_plain(rect.location() + Point::new(rect.width(), y), chars::VLINE);
        }
    }

    #[allow(unused)]
    fn draw_map(&self, game: &mut Game, console: &mut Console) {
        let map = &game.world.map;

        let (ux, uy): (usize, usize) = self.map_view.as_tuple();
        let (width, height) = self.map_frame.size().as_tuple();

        for (y, line) in map.tiles[uy .. uy + height].iter().enumerate() {
            for (x, cell) in line[ux .. ux + width].iter().enumerate() {
                console.put(self.map_frame.location() + Point::new(x as i32, y as i32), ' ', Colors::white, cell.b_color());
            }
        }
    }

    #[allow(unused)]
    fn draw_player(&mut self, game: &mut Game, console: &mut Console) {
        let repr = game.world.player.repr;
        let pos = game.world.player.pos;

        let adjusted_pos = pos + self.map_frame.location() - self.map_view;

        if adjusted_pos.x >= self.map_frame.location().x + self.map_frame.width() - 10 {
            if self.view_can_move_right(game) {
                self.map_view = self.map_view.right(1);
            }
        }

        if adjusted_pos.y >= self.map_frame.location().y + self.map_frame.height() - 5 {
            if self.view_can_move_down(game) {
                self.map_view = self.map_view.down(1);
            }
        }

        if adjusted_pos.y <= self.map_frame.location().y + 5 {
            if self.view_can_move_up(game) {
                self.map_view = self.map_view.up(1);
            }
        }

        if adjusted_pos.x <= self.map_frame.location().x + 10 {
            if self.view_can_move_left(game) {
                self.map_view = self.map_view.left(1);
            }
        }

        if adjusted_pos.x >= self.map_frame.location().x && adjusted_pos.y >= self.map_frame.location().y {
            console.put_plain(self.map_frame.location() - self.map_view + pos, repr);
        }
    }

    #[allow(unused)]
    fn view_can_move_up(&self, game: &Game) -> bool {
        self.map_view.y  > 0
    }

    #[allow(unused)]
    fn view_can_move_down(&self, game: &Game) -> bool {
        self.map_view.y + self.map_frame.height() < game.world.map.height()
    }

    #[allow(unused)]
    fn view_can_move_left(&self, game: &Game) -> bool {
        self.map_view.x > 0
    }

    #[allow(unused)]
    fn view_can_move_right(&self, game: &Game) -> bool {
        self.map_view.x + self.map_frame.width() < game.world.map.width()
    }

}
<|endoftext|>


<commit_before>//! Various definitions of types, constants, traint, ... related to network

use core::fmt::{
    Binary,
    Octal,
    LowerHex,
    UpperHex,
    Debug,
    Display,
    Formatter,
    Error
};

use num::PrimInt;

/// Network integer representation
///
/// This type stores an integer using network's endianness and let the user
/// manipulates it using host's endianness.
#[derive(Clone)]
#[repr(C, packed)]
pub struct Int<T: PrimInt + Clone>(T);

impl<T> Int<T> where T: PrimInt + Clone {
    /// Construct from an integer represented using network's endianness
    pub fn from_net(i: T) -> Self {
        Int(i)
    }

    /// Construct from an integer represented using host's endianness
    pub fn from_host(i: T) -> Self {
        Int(i.to_be())
    }

    /// Returns the contained integer using host's endianness
    pub fn as_host(&self) -> T {
        T::from_be(self.0.clone())
    }

    /// Returns the contained integer using network's endianness
    pub fn as_net(&self) -> T {
        self.0.clone()
    }
}

impl<T> Binary for Int<T> where T: PrimInt + Clone + Binary {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Octal for Int<T> where T: PrimInt + Clone + Octal {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> LowerHex for Int<T> where T: PrimInt + Clone + LowerHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> UpperHex for Int<T> where T: PrimInt + Clone + UpperHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Debug for Int<T> where T: PrimInt + Clone + Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Display for Int<T> where T: PrimInt + Clone + Display {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

const COUNT_HWADDR_BYTES: usize = 6;

#[repr(C, packed)]
#[derive(Copy, Clone)]
/// A MAC address
pub struct HwAddr {
    bytes: [u8; COUNT_HWADDR_BYTES],
}

impl HwAddr {
    /// Create an empty hardware address (i.e., 00:00:00:00:00:00)
    pub fn empty() -> Self {
        HwAddr {
            bytes: [0; COUNT_HWADDR_BYTES],
        }
    }

    /// Create an hardware address from bytes.
    ///
    /// This method is unsafe because the slice *MUST* contain at least 6
    /// elements.
    pub unsafe fn from_bytes(bytes: &[u8]) -> Self {
        let mut ret = Self::empty();

        ret.bytes[0] = bytes[0];
        ret.bytes[1] = bytes[1];
        ret.bytes[2] = bytes[2];
        ret.bytes[3] = bytes[3];
        ret.bytes[4] = bytes[4];
        ret.bytes[5] = bytes[5];

        ret
    }

    #[inline]
    /// Returns the internal representation of an hardware address
    pub fn as_bytes(&self) -> &[u8] {
        &self.bytes[..]
    }
}

impl PartialEq for HwAddr {
    fn eq(&self, rhs: &Self) -> bool {
        self.bytes[0] == rhs.bytes[0] &&
        self.bytes[1] == rhs.bytes[1] &&
        self.bytes[2] == rhs.bytes[2] &&
        self.bytes[3] == rhs.bytes[3] &&
        self.bytes[4] == rhs.bytes[4] &&
        self.bytes[5] == rhs.bytes[5]
    }
}

impl Display for HwAddr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", self.bytes[0],
                                 self.bytes[1], self.bytes[2], self.bytes[3],
                                 self.bytes[4], self.bytes[5]))
    }
}
<commit_msg>net: Update Display for HwAddr<commit_after>//! Various definitions of types, constants, traint, ... related to network

use core::fmt::{
    Binary,
    Octal,
    LowerHex,
    UpperHex,
    Debug,
    Display,
    Formatter,
    Error
};

use num::PrimInt;

/// Network integer representation
///
/// This type stores an integer using network's endianness and let the user
/// manipulates it using host's endianness.
#[derive(Clone)]
#[repr(C, packed)]
pub struct Int<T: PrimInt + Clone>(T);

impl<T> Int<T> where T: PrimInt + Clone {
    /// Construct from an integer represented using network's endianness
    pub fn from_net(i: T) -> Self {
        Int(i)
    }

    /// Construct from an integer represented using host's endianness
    pub fn from_host(i: T) -> Self {
        Int(i.to_be())
    }

    /// Returns the contained integer using host's endianness
    pub fn as_host(&self) -> T {
        T::from_be(self.0.clone())
    }

    /// Returns the contained integer using network's endianness
    pub fn as_net(&self) -> T {
        self.0.clone()
    }
}

impl<T> Binary for Int<T> where T: PrimInt + Clone + Binary {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Octal for Int<T> where T: PrimInt + Clone + Octal {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> LowerHex for Int<T> where T: PrimInt + Clone + LowerHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> UpperHex for Int<T> where T: PrimInt + Clone + UpperHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Debug for Int<T> where T: PrimInt + Clone + Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Display for Int<T> where T: PrimInt + Clone + Display {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

const COUNT_HWADDR_BYTES: usize = 6;

#[repr(C, packed)]
#[derive(Copy, Clone)]
/// A MAC address
pub struct HwAddr {
    bytes: [u8; COUNT_HWADDR_BYTES],
}

impl HwAddr {
    /// Create an empty hardware address (i.e., 00:00:00:00:00:00)
    pub fn empty() -> Self {
        HwAddr {
            bytes: [0; COUNT_HWADDR_BYTES],
        }
    }

    /// Create an hardware address from bytes.
    ///
    /// This method is unsafe because the slice *MUST* contain at least 6
    /// elements.
    pub unsafe fn from_bytes(bytes: &[u8]) -> Self {
        let mut ret = Self::empty();

        ret.bytes[0] = bytes[0];
        ret.bytes[1] = bytes[1];
        ret.bytes[2] = bytes[2];
        ret.bytes[3] = bytes[3];
        ret.bytes[4] = bytes[4];
        ret.bytes[5] = bytes[5];

        ret
    }

    #[inline]
    /// Returns the internal representation of an hardware address
    pub fn as_bytes(&self) -> &[u8] {
        &self.bytes[..]
    }
}

impl PartialEq for HwAddr {
    fn eq(&self, rhs: &Self) -> bool {
        self.bytes[0] == rhs.bytes[0] &&
        self.bytes[1] == rhs.bytes[1] &&
        self.bytes[2] == rhs.bytes[2] &&
        self.bytes[3] == rhs.bytes[3] &&
        self.bytes[4] == rhs.bytes[4] &&
        self.bytes[5] == rhs.bytes[5]
    }
}

impl Display for HwAddr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
                                 self.bytes[0], self.bytes[1], self.bytes[2],
                                 self.bytes[3], self.bytes[4], self.bytes[5]))
    }
}
<|endoftext|>


<commit_before>use std::libc::*;
use std::cast::transmute;
use std::hashmap::HashMap;

use state::State;
use types::*;
use lua::Lua;

/**
 *  A generic trait for converting a Lua value to a Rust value.
 *
 *  Return None when the types didn't corresponds.
 */
pub trait FromLua
{
    fn from_lua(state: &State, idx: int) -> Option<Self>;
}

/// A generic trait for converting a Rust value to a Lua value.
pub trait ToLua
{
    fn to_lua(&self, state: &State);
}

// float
impl FromLua for f64
{
    fn from_lua(state: &State, idx: int) -> Option<f64>
    {
        match state.get_type(idx)
        {
            LuaNumber => Some(state.get_float(idx)),
            _ => None,
        }
    }
}

impl ToLua for f64
{
    fn to_lua(&self, state: &State)
    {
        state.push_float(*self);
    }
}

// int
impl FromLua for int
{
    fn from_lua(state: &State, idx: int) -> Option<int>
    {
        match state.get_type(idx)
        {
            LuaNumber => Some(state.get_int(idx)),
            _ => None,
        }
    }
}

impl ToLua for int
{
    fn to_lua(&self, state: &State)
    {
        state.push_int(*self);
    }
}

// uint
impl FromLua for uint
{
    fn from_lua(state: &State, idx: int) -> Option<uint>
    {
        match state.get_type(idx)
        {
            LuaNumber => Some(state.get_uint(idx)),
            _ => None,
        }
    }
}

impl ToLua for uint
{
    fn to_lua(&self, state: &State)
    {
        state.push_uint(*self);
    }
}

// &str
impl<'a> ToLua for &'a str
{
    fn to_lua(&self, state: &State)
    {
        state.push_str(*self);
    }
}

// ~str
impl FromLua for ~str
{
    fn from_lua(state: &State, idx: int) -> Option<~str>
    {
        match state.get_type(idx)
        {
            LuaString => Some(state.get_str(idx)),
            _ => None,
        }
    }
}

impl ToLua for ~str
{
    fn to_lua(&self, state: &State)
    {
        state.push_str(*self);
    }
}

// bool
impl FromLua for bool
{
    fn from_lua(state: &State, idx: int) -> Option<bool>
    {
        match state.get_type(idx)
        {
            LuaBoolean => Some(state.get_bool(idx)),
            _ => None,
        }
    }
}

impl ToLua for bool
{
    fn to_lua(&self, state: &State)
    {
        state.push_bool(*self);
    }
}

// Pointer
impl<T> FromLua for *T
{
    fn from_lua(state: &State, idx: int) -> Option<*T>
    {
        match state.get_type(idx)
        {
            LuaUserData | LuaLightUserData => Some(state.get_userdata(idx)),
            _ => None,
        }
    }
}

impl<T> ToLua for *T
{
    fn to_lua(&self, state: &State)
    {
        state.push_userdata(*self);
    }
}

// Function
impl FromLua for fn(l: &Lua) -> int
{
    fn from_lua(state: &State, idx: int) -> Option<fn(l: &Lua) -> int>
    {
        match state.get_type(idx)
        {
            LuaUserData | LuaLightUserData => {
                let ptr: fn(&Lua) -> int = unsafe {
                    transmute(state.get_userdata::<*c_void>(idx))
                };

                Some(ptr)
            }
            _ => None,
        }
    }
}

impl ToLua for fn(l: &Lua) -> int
{
    fn to_lua(&self, state: &State)
    {
        state.push_function(*self);
    }
}

// HashMap
impl<K: ToLua + Hash + Eq, V: ToLua> ToLua for HashMap<K, V>
{
    fn to_lua(&self, state: &State)
    {
        state.new_table();

        for (ref key, ref val) in self.iter()
        {
            key.to_lua(state);
            val.to_lua(state);
            state.raw_set(-3);
        }
    }
}

impl<K: FromLua + Hash + Eq, V: FromLua> FromLua for HashMap<K, V>
{
    fn from_lua(state: &State, idx: int) -> Option<HashMap<K, V>>
    {
        let mut map: HashMap<K, V> = HashMap::new();

        state.push_nil();
        while state.next(idx - 1)
        {
            let key: K = match FromLua::from_lua(state, -2) {
                Some(k) => k,
                None => {
                    return None;
                }
            };
            let val: V = match FromLua::from_lua(state, -1) {
                Some(v) => v,
                None => {
                    return None;
                }
            };
            map.insert(key, val);

            state.pop(1);
        }

        Some(map)
    }
}

// Array
impl<'a, T: ToLua> ToLua for &'a [T]
{
    fn to_lua(&self, state: &State)
    {
        state.new_table();

        for (i, ref val) in self.iter().enumerate()
        {
            state.push_uint(i + 1);
            val.to_lua(state);
            state.raw_set(-3);
        }
    }
}

impl<T: FromLua> FromLua for ~[T]
{
    fn from_lua(state: &State, idx: int) -> Option<~[T]>
    {
        let mut v = ~[];
        let length = state.len(idx);

        let mut i = 1;
        while i <= length
        {
            state.push_int(i);

            let val: T = match FromLua::from_lua(state, -1) {
                Some(val) => val,
                None => {
                    return None;
                }
            };
            v.push(val);

            i += 1;
        }

        Some(v)
    }
}
<commit_msg>Fix Hash trait usage.<commit_after>use std::libc::*;
use std::cast::transmute;
use std::hashmap::HashMap;
use std::hash::Hash;

use state::State;
use types::*;
use lua::Lua;

/**
 *  A generic trait for converting a Lua value to a Rust value.
 *
 *  Return None when the types didn't corresponds.
 */
pub trait FromLua
{
    fn from_lua(state: &State, idx: int) -> Option<Self>;
}

/// A generic trait for converting a Rust value to a Lua value.
pub trait ToLua
{
    fn to_lua(&self, state: &State);
}

// float
impl FromLua for f64
{
    fn from_lua(state: &State, idx: int) -> Option<f64>
    {
        match state.get_type(idx)
        {
            LuaNumber => Some(state.get_float(idx)),
            _ => None,
        }
    }
}

impl ToLua for f64
{
    fn to_lua(&self, state: &State)
    {
        state.push_float(*self);
    }
}

// int
impl FromLua for int
{
    fn from_lua(state: &State, idx: int) -> Option<int>
    {
        match state.get_type(idx)
        {
            LuaNumber => Some(state.get_int(idx)),
            _ => None,
        }
    }
}

impl ToLua for int
{
    fn to_lua(&self, state: &State)
    {
        state.push_int(*self);
    }
}

// uint
impl FromLua for uint
{
    fn from_lua(state: &State, idx: int) -> Option<uint>
    {
        match state.get_type(idx)
        {
            LuaNumber => Some(state.get_uint(idx)),
            _ => None,
        }
    }
}

impl ToLua for uint
{
    fn to_lua(&self, state: &State)
    {
        state.push_uint(*self);
    }
}

// &str
impl<'a> ToLua for &'a str
{
    fn to_lua(&self, state: &State)
    {
        state.push_str(*self);
    }
}

// ~str
impl FromLua for ~str
{
    fn from_lua(state: &State, idx: int) -> Option<~str>
    {
        match state.get_type(idx)
        {
            LuaString => Some(state.get_str(idx)),
            _ => None,
        }
    }
}

impl ToLua for ~str
{
    fn to_lua(&self, state: &State)
    {
        state.push_str(*self);
    }
}

// bool
impl FromLua for bool
{
    fn from_lua(state: &State, idx: int) -> Option<bool>
    {
        match state.get_type(idx)
        {
            LuaBoolean => Some(state.get_bool(idx)),
            _ => None,
        }
    }
}

impl ToLua for bool
{
    fn to_lua(&self, state: &State)
    {
        state.push_bool(*self);
    }
}

// Pointer
impl<T> FromLua for *T
{
    fn from_lua(state: &State, idx: int) -> Option<*T>
    {
        match state.get_type(idx)
        {
            LuaUserData | LuaLightUserData => Some(state.get_userdata(idx)),
            _ => None,
        }
    }
}

impl<T> ToLua for *T
{
    fn to_lua(&self, state: &State)
    {
        state.push_userdata(*self);
    }
}

// Function
impl FromLua for fn(l: &Lua) -> int
{
    fn from_lua(state: &State, idx: int) -> Option<fn(l: &Lua) -> int>
    {
        match state.get_type(idx)
        {
            LuaUserData | LuaLightUserData => {
                let ptr: fn(&Lua) -> int = unsafe {
                    transmute(state.get_userdata::<*c_void>(idx))
                };

                Some(ptr)
            }
            _ => None,
        }
    }
}

impl ToLua for fn(l: &Lua) -> int
{
    fn to_lua(&self, state: &State)
    {
        state.push_function(*self);
    }
}

// HashMap
impl<K: ToLua + Hash + IterBytes + Eq, V: ToLua> ToLua for HashMap<K, V>
{
    fn to_lua(&self, state: &State)
    {
        state.new_table();

        for (ref key, ref val) in self.iter()
        {
            key.to_lua(state);
            val.to_lua(state);
            state.raw_set(-3);
        }
    }
}

impl<K: FromLua + Hash + IterBytes + Eq, V: FromLua> FromLua for HashMap<K, V>
{
    fn from_lua(state: &State, idx: int) -> Option<HashMap<K, V>>
    {
        let mut map: HashMap<K, V> = HashMap::new();

        state.push_nil();
        while state.next(idx - 1)
        {
            let key: K = match FromLua::from_lua(state, -2) {
                Some(k) => k,
                None => {
                    return None;
                }
            };
            let val: V = match FromLua::from_lua(state, -1) {
                Some(v) => v,
                None => {
                    return None;
                }
            };
            map.insert(key, val);

            state.pop(1);
        }

        Some(map)
    }
}

// Array
impl<'a, T: ToLua> ToLua for &'a [T]
{
    fn to_lua(&self, state: &State)
    {
        state.new_table();

        for (i, ref val) in self.iter().enumerate()
        {
            state.push_uint(i + 1);
            val.to_lua(state);
            state.raw_set(-3);
        }
    }
}

impl<T: FromLua> FromLua for ~[T]
{
    fn from_lua(state: &State, idx: int) -> Option<~[T]>
    {
        let mut v = ~[];
        let length = state.len(idx);

        let mut i = 1;
        while i <= length
        {
            state.push_int(i);

            let val: T = match FromLua::from_lua(state, -1) {
                Some(val) => val,
                None => {
                    return None;
                }
            };
            v.push(val);

            i += 1;
        }

        Some(v)
    }
}
<|endoftext|>


<commit_before>use std::collections::{RingBuf, HashSet};
use std::mem;
use std::ptr;

use block_allocator::BlockAllocator;
use block_info::BlockInfo;
use constants::{BLOCK_SIZE, LINE_SIZE};
use gc_object::GCObject;

pub struct LineAllocator {
    block_allocator: BlockAllocator,
    object_map: HashSet<*mut GCObject>,
    unavailable_blocks: RingBuf<*mut BlockInfo>,
    recyclable_blocks: RingBuf<*mut BlockInfo>,
    current_block: Option<(*mut BlockInfo, u16, u16)>,
}

impl LineAllocator {
    pub fn new(block_allocator: BlockAllocator) -> LineAllocator {
        return LineAllocator {
            block_allocator: block_allocator,
            object_map: HashSet::new(),
            unavailable_blocks: RingBuf::new(),
            recyclable_blocks: RingBuf::new(),
            current_block: None,
        };
    }

    pub fn is_gc_object(&self, object: *mut GCObject) -> bool {
        return self.object_map.contains(&object);
    }

    pub fn allocate(&mut self, size: uint, variables: uint) -> Option<*mut GCObject> {
        debug!("Request to allocate an object of size {}", size);
        let block_tuple = self.current_block
                              .and_then(|tp| self.scan_for_hole(size, tp))
                              .or_else(|| self.scan_recyclables(size))
                              .or_else(|| self.get_new_block());
        return match block_tuple {
            None => None,
            Some((block, low, high)) => {
                self.current_block = Some((block, low + size as u16, high));
                let object = unsafe { (*block).offset(low as uint) };
                self.object_map.insert(object);
                unsafe { ptr::write(object, GCObject::new(size, variables)); }
                debug!("Allocated object {} of size {} in {}", object, size, block);
                Some(object)
            }
        };
    }

    fn scan_for_hole(&mut self, size: uint, tuple: (*mut BlockInfo, u16, u16))
        -> Option<(*mut BlockInfo, u16, u16)> {
            let (block, low, high) = tuple;
            return match (high - low) as uint >= size {
                true => {
                    debug!("Found hole in block {:p}", block);
                    Some(tuple)
                },
                false => match unsafe{ (*block).scan_block(high) } {
                    None => {
                        debug!("Push block {:p} into unavailable_blocks", block);
                        self.unavailable_blocks.push_back(block);
                        None
                    },
                    Some((low, high)) =>
                        self.scan_for_hole(size, (block, low, high)),
                }
            };
        }

    fn scan_recyclables(&mut self, size: uint) -> Option<(*mut BlockInfo, u16, u16)> {
        return match self.recyclable_blocks.pop_front() {
            None => None,
            Some(block) => match unsafe{ (*block).scan_block((LINE_SIZE - 1) as u16) } {
                None => {
                    debug!("Push block {:p} into unavailable_blocks", block);
                    self.unavailable_blocks.push_back(block);
                    self.scan_recyclables(size)
                },
                Some((low, high)) => self.scan_for_hole(size, (block, low, high))
                                         .or_else(|| self.scan_recyclables(size)),
            }
        };
    }

    fn get_new_block(&mut self) -> Option<(*mut BlockInfo, u16, u16)> {
        debug!("Request new block from block_allocator");
        return self.block_allocator.get_block()
                   .map(|block| (block, LINE_SIZE as u16, (BLOCK_SIZE - 1) as u16));
    }

    pub fn return_empty_blocks(&mut self) {
        if let Some((block, _, _)) = self.current_block.take() {
            self.unavailable_blocks.push_back(block);
        }
        for block in self.unavailable_blocks.drain() {
            if unsafe{ (*block).is_empty() } {
                debug!("Return block {:p} to global block allocator", block);
                self.block_allocator.return_block(block);
            } else {
                debug!("Recycle block {:p}", block);
                self.recyclable_blocks.push_back(block);
            }
        }
    }

    unsafe fn get_block_ptr(&mut self, object: *mut GCObject) -> *mut BlockInfo {
        let block_offset = object as uint % BLOCK_SIZE;
        return mem::transmute((object as *mut u8).offset(-(block_offset as int)));
    }

    pub fn decrement_lines(&mut self, object: *mut GCObject) {
        unsafe{
            let block_ptr = self.get_block_ptr(object);
            (*block_ptr).decrement_lines(object);
        }
    }

    pub fn increment_lines(&mut self, object: *mut GCObject) {
        unsafe{
            let block_ptr = self.get_block_ptr(object);
            (*block_ptr).increment_lines(object);
        }
    }
}
<commit_msg>LineAllocator: also process recyclables in return_empty_blocks()<commit_after>use std::collections::{RingBuf, HashSet};
use std::mem;
use std::ptr;

use block_allocator::BlockAllocator;
use block_info::BlockInfo;
use constants::{BLOCK_SIZE, LINE_SIZE};
use gc_object::GCObject;

pub struct LineAllocator {
    block_allocator: BlockAllocator,
    object_map: HashSet<*mut GCObject>,
    unavailable_blocks: RingBuf<*mut BlockInfo>,
    recyclable_blocks: RingBuf<*mut BlockInfo>,
    current_block: Option<(*mut BlockInfo, u16, u16)>,
}

impl LineAllocator {
    pub fn new(block_allocator: BlockAllocator) -> LineAllocator {
        return LineAllocator {
            block_allocator: block_allocator,
            object_map: HashSet::new(),
            unavailable_blocks: RingBuf::new(),
            recyclable_blocks: RingBuf::new(),
            current_block: None,
        };
    }

    pub fn is_gc_object(&self, object: *mut GCObject) -> bool {
        return self.object_map.contains(&object);
    }

    pub fn allocate(&mut self, size: uint, variables: uint) -> Option<*mut GCObject> {
        debug!("Request to allocate an object of size {}", size);
        let block_tuple = self.current_block
                              .and_then(|tp| self.scan_for_hole(size, tp))
                              .or_else(|| self.scan_recyclables(size))
                              .or_else(|| self.get_new_block());
        return match block_tuple {
            None => None,
            Some((block, low, high)) => {
                self.current_block = Some((block, low + size as u16, high));
                let object = unsafe { (*block).offset(low as uint) };
                self.object_map.insert(object);
                unsafe { ptr::write(object, GCObject::new(size, variables)); }
                debug!("Allocated object {} of size {} in {}", object, size, block);
                Some(object)
            }
        };
    }

    fn scan_for_hole(&mut self, size: uint, tuple: (*mut BlockInfo, u16, u16))
        -> Option<(*mut BlockInfo, u16, u16)> {
            let (block, low, high) = tuple;
            return match (high - low) as uint >= size {
                true => {
                    debug!("Found hole in block {:p}", block);
                    Some(tuple)
                },
                false => match unsafe{ (*block).scan_block(high) } {
                    None => {
                        debug!("Push block {:p} into unavailable_blocks", block);
                        self.unavailable_blocks.push_back(block);
                        None
                    },
                    Some((low, high)) =>
                        self.scan_for_hole(size, (block, low, high)),
                }
            };
        }

    fn scan_recyclables(&mut self, size: uint) -> Option<(*mut BlockInfo, u16, u16)> {
        return match self.recyclable_blocks.pop_front() {
            None => None,
            Some(block) => match unsafe{ (*block).scan_block((LINE_SIZE - 1) as u16) } {
                None => {
                    debug!("Push block {:p} into unavailable_blocks", block);
                    self.unavailable_blocks.push_back(block);
                    self.scan_recyclables(size)
                },
                Some((low, high)) => self.scan_for_hole(size, (block, low, high))
                                         .or_else(|| self.scan_recyclables(size)),
            }
        };
    }

    fn get_new_block(&mut self) -> Option<(*mut BlockInfo, u16, u16)> {
        debug!("Request new block from block_allocator");
        return self.block_allocator.get_block()
                   .map(|block| (block, LINE_SIZE as u16, (BLOCK_SIZE - 1) as u16));
    }

    pub fn return_empty_blocks(&mut self) {
        let mut recyclable_blocks = RingBuf::new();
        for block in self.current_block.take().map(|(b, _, _)| b).into_iter()
                         .chain(self.recyclable_blocks.drain())
                         .chain(self.unavailable_blocks.drain()) {
            if unsafe{ (*block).is_empty() } {
                debug!("Return block {:p} to global block allocator", block);
                self.block_allocator.return_block(block);
            } else {
                debug!("Recycle block {:p}", block);
                recyclable_blocks.push_back(block);
            }
        }
        self.recyclable_blocks.extend(recyclable_blocks.into_iter());
    }

    unsafe fn get_block_ptr(&mut self, object: *mut GCObject) -> *mut BlockInfo {
        let block_offset = object as uint % BLOCK_SIZE;
        return mem::transmute((object as *mut u8).offset(-(block_offset as int)));
    }

    pub fn decrement_lines(&mut self, object: *mut GCObject) {
        unsafe{
            let block_ptr = self.get_block_ptr(object);
            (*block_ptr).decrement_lines(object);
        }
    }

    pub fn increment_lines(&mut self, object: *mut GCObject) {
        unsafe{
            let block_ptr = self.get_block_ptr(object);
            (*block_ptr).increment_lines(object);
        }
    }
}
<|endoftext|>