<commit_before>//! [Church-encoded numerals](https://en.wikipedia.org/wiki/Church_encoding#Church_numerals)

use term::*;
use term::Term::*;
use term::Error::*;
use booleans::*;

/// Produces a Church-encoded zero.
///
/// ZERO := λfx.x = λ λ 1
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::zero;
///
/// assert_eq!(format!("{}", zero()), "λλ1");
/// ```
pub fn zero() -> Term { abs(abs(Var(1))) }

/// Applied to a Church-encoded number it produces a Church-encoded boolean, indicating whether its
/// argument is equal to zero.
///
/// IS_ZERO := λn.n (λx.FALSE) TRUE =  λ 1 (λ FALSE) TRUE
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{zero, is_zero};
/// use lambda_calculus::booleans::tru;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(is_zero().app(zero())), tru());
/// ```
pub fn is_zero() -> Term { abs(Var(1).app(abs(fls())).app(tru())) }

/// Produces a Church-encoded one.
///
/// ONE := λfx.f x = λ λ 2 1
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::one;
///
/// assert_eq!(format!("{}", one()), "λλ21");
/// ```
pub fn one() -> Term { abs(abs(Var(2).app(Var(1)))) }

/// Applied to a Church-encoded number it produces its successor.
///
/// SUCC := λnfx.f (n f x) = λ λ λ 2 (3 2 1)
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{zero, one, succ};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(succ().app(zero())), one());
/// ```
pub fn succ() -> Term { abs(abs(abs(Var(2).app(Var(3).app(Var(2)).app(Var(1)))))) }

/// Applied to two Church-encoded numbers it produces their sum.
///
/// PLUS := λmnfx.m f (n f x) = λ λ λ λ 4 2 (3 2 1)
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{zero, one, plus};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(plus().app(zero()).app(one())), one());
/// ```
pub fn plus() -> Term { abs(abs(abs(abs(Var(4).app(Var(2)).app(Var(3).app(Var(2)).app(Var(1))))))) }

/// Applied to two Church-encoded numbers it produces their product.
///
/// MULT := λmnf.m (n f) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{one, mult};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(mult().app(one()).app(one())), one());
/// ```
pub fn mult() -> Term { abs(abs(abs(Var(3).app(Var(2).app(Var(1)))))) }

/// Applied to two Church-encoded numbers it raises the first one to the power of the second one.
///
/// POW := λbe.e b = λ λ 1 2
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{one, pow};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(pow().app(one()).app(one())), one());
/// ```
pub fn pow() -> Term { abs(abs(Var(1).app(Var(2)))) }

/// Applied to a Church-encoded number it produces its predecessor.
///
/// PRED := λnfx.n (λgh.h (g f)) (λu.x) (λu.u) = λ λ λ 3 (λ λ 1 (2 4)) (λ 2) (λ 1)
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{zero, one, pred};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(pred().app(one())), zero());
/// ```
pub fn pred() -> Term { abs(abs(abs(Var(3).app(abs(abs(Var(1).app(Var(2).app(Var(4)))))).app(abs(Var(2))).app(abs(Var(1)))))) }

/// Applied to two Church-encoded numbers it subtracts the second one from the first one.
///
/// SUB := λmn.n PRED m = λ λ 1 PRED 2
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{zero, one, sub};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(sub().app(one()).app(zero())), one());
/// ```
pub fn sub() -> Term { abs(abs(Var(1).app(pred()).app(Var(2)))) }

/// Applied to two Church-encoded numbers it returns a Church-encoded boolean indicating whether its
/// first argument is less or egual to the second one.
///
/// LEQ := λmn.IS_ZERO (SUB m n) = λ λ IS_ZERO (SUB 2 1)
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{zero, one, leq};
/// use lambda_calculus::booleans::tru;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(leq().app(zero()).app(one())), tru());
/// ```
pub fn leq() -> Term { abs(abs(is_zero().app(sub().app(Var(2)).app(Var(1))))) }

/// Applied to two Church-encoded numbers it returns a Church-encoded boolean indicating whether its
/// first argument is egual to the second one.
///
/// EQ := λmn.AND (LEQ m n) (LEQ n m) = λ λ AND (LEQ 2 1) (LEQ 1 2)
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{one, eq};
/// use lambda_calculus::booleans::tru;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(eq().app(one()).app(one())), tru());
/// ```
pub fn eq() -> Term { abs(abs(and().app(leq().app(Var(2)).app(Var(1))).app(leq().app(Var(1)).app(Var(2))))) }

impl Term {
	/// Returns the value of a Church-encoded number.
	///
	/// # Example
	/// ```
	/// use lambda_calculus::arithmetic::one;
	///
	/// assert_eq!(one().value(), Ok(1));
	/// ```
	pub fn value(&self) -> Result<usize, Error> {
		if let Ok(ref inner) = self.unabs_ref().and_then(|t| t.unabs_ref()) {
			Ok(try!(inner._value()))
		} else {
			Err(NotANum)
		}
	}

	fn _value(&self) -> Result<usize, Error> {
		if let Ok(ref rhs) = self.rhs_ref() {
			Ok(1 + try!(rhs._value()))
		} else if let Var(n) = *self {
			if n == 1 {
				Ok(0)
			} else {
				Err(NotANum)
			}
		} else {
			Err(NotANum)
		}
	}

	/// Checks whether a term is a Church-encoded number.
	///
	/// # Example
	/// ```
	/// use lambda_calculus::arithmetic::one;
	///
	/// assert!(one().is_number());
	/// ```
	pub fn is_number(&self) -> bool { self.value().is_ok() }
}

/// Produces a Church-encoded term with a value of the given natural number.
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{one, to_cnum};
///
/// assert_eq!(to_cnum(1), one());
/// ```
pub fn to_cnum(n: usize) -> Term {
	let mut inner = Var(1);
	let mut count = n;

	while count > 0 {
		inner = Var(2).app(inner);
		count -= 1;
	}

	abs(abs(inner))
}

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

	#[test]
	fn church_zero() {
		assert_eq!(normalize(is_zero().app(zero())), tru());
		assert_eq!(normalize(is_zero().app(one())), fls());
	}

	#[test]
	fn church_successor() {
		assert_eq!(normalize(succ().app(zero())), one());
		assert_eq!(normalize(succ().app(one())), abs(abs(Var(2).app(Var(2).app(Var(1))))));
		assert_eq!(normalize(succ().app(succ().app(succ().app(zero())))), abs(abs(Var(2).app(Var(2).app(Var(2).app(Var(1)))))));
	}

	#[test]
	fn church_number_identification() {
		for n in 0..5 { assert!(to_cnum(n).is_number()) }
	}

	#[test]
	fn church_number_creation() {
		assert_eq!(to_cnum(0), zero());
		assert_eq!(to_cnum(1), one());
		assert_eq!(to_cnum(2), normalize(succ().app(one())));
	}

	#[test]
	fn church_number_values() {
		for n in 0..10 { assert_eq!(to_cnum(n).value(), Ok(n)) }

		assert_eq!(tru().value(),		Err(NotANum));
		assert_eq!(Var(1).value(),		Err(NotANum));
		assert_eq!(abs(Var(1)).value(),	Err(NotANum));
	}

	#[test]
	fn church_addition() {
		assert_eq!(normalize(plus().app(one())), succ()); // PLUS 1 → SUCC

		assert_eq!(normalize(plus().app(zero()).app(zero())), zero());
		assert_eq!(normalize(plus().app(zero()).app(one())),  one());
		assert_eq!(normalize(plus().app(one()).app(zero())),  one());
		assert_eq!(normalize(plus().app(one()).app(one())),   to_cnum(2));

		assert_eq!(normalize(plus().app(to_cnum(2)).app(to_cnum(3))), to_cnum(5));
		assert_eq!(normalize(plus().app(to_cnum(4)).app(to_cnum(4))), to_cnum(8));
	}

	#[test]
	fn church_multiplication() {
		assert_eq!(normalize(mult().app(to_cnum(3)).app(to_cnum(4))), to_cnum(12));
		assert_eq!(normalize(mult().app(to_cnum(1)).app(to_cnum(3))), to_cnum(3));
		assert_eq!(normalize(mult().app(to_cnum(5)).app(to_cnum(0))), to_cnum(0));
	}

	#[test]
	fn church_exponentiation() {
		assert_eq!(normalize(pow().app(to_cnum(2)).app(to_cnum(4))), to_cnum(16));
		assert_eq!(normalize(pow().app(to_cnum(1)).app(to_cnum(6))), to_cnum(1));
		assert_eq!(normalize(pow().app(to_cnum(3)).app(to_cnum(2))), to_cnum(9));
		assert_eq!(normalize(pow().app(to_cnum(4)).app(to_cnum(1))), to_cnum(4));
//		assert_eq!(normalize(pow().app(to_cnum(5)).app(zero())),	 to_cnum(1)); // n^0 fails - why?
	}

	#[test]
	fn church_subtraction() {
		assert_eq!(normalize(sub().app(zero()).app(zero())),	zero());
		assert_eq!(normalize(sub().app(zero()).app(one())),		zero());
		assert_eq!(normalize(sub().app(one()).app(zero())),		one());
		assert_eq!(normalize(sub().app(to_cnum(2)).app(one())), one());

		assert_eq!(normalize(sub().app(to_cnum(5)).app(to_cnum(3))), to_cnum(2));
		assert_eq!(normalize(sub().app(to_cnum(8)).app(to_cnum(4))), to_cnum(4));
	}

	#[test]
	fn church_predecessor() {
		assert_eq!(normalize(pred().app(zero())), zero());
		assert_eq!(normalize(pred().app(one())), zero());
		assert_eq!(normalize(pred().app(to_cnum(5))), to_cnum(4));
	}

	#[test]
	fn church_comparison() {
		assert_eq!(normalize(leq().app(zero()).app(zero())), tru());
		assert_eq!(normalize(leq().app(zero()).app(one())),  tru());
		assert_eq!(normalize(leq().app(one()).app(zero())),  fls());

		assert_eq!(normalize(eq().app(zero()).app(zero())), tru());
		assert_eq!(normalize(eq().app(zero()).app(one())),  fls());
		assert_eq!(normalize(eq().app(one()).app(zero())),  fls());
		// TODO: add lt, gt, geq
	}
}
<commit_msg>Add LT to arithmetic.rs<commit_after>//! [Church-encoded numerals](https://en.wikipedia.org/wiki/Church_encoding#Church_numerals)

use term::*;
use term::Term::*;
use term::Error::*;
use booleans::*;

/// Produces a Church-encoded zero.
///
/// ZERO := λfx.x = λ λ 1
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::zero;
///
/// assert_eq!(format!("{}", zero()), "λλ1");
/// ```
pub fn zero() -> Term { abs(abs(Var(1))) }

/// Applied to a Church-encoded number it produces a Church-encoded boolean, indicating whether its
/// argument is equal to zero.
///
/// IS_ZERO := λn.n (λx.FALSE) TRUE =  λ 1 (λ FALSE) TRUE
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{zero, is_zero};
/// use lambda_calculus::booleans::tru;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(is_zero().app(zero())), tru());
/// ```
pub fn is_zero() -> Term { abs(Var(1).app(abs(fls())).app(tru())) }

/// Produces a Church-encoded one.
///
/// ONE := λfx.f x = λ λ 2 1
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::one;
///
/// assert_eq!(format!("{}", one()), "λλ21");
/// ```
pub fn one() -> Term { abs(abs(Var(2).app(Var(1)))) }

/// Applied to a Church-encoded number it produces its successor.
///
/// SUCC := λnfx.f (n f x) = λ λ λ 2 (3 2 1)
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{zero, one, succ};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(succ().app(zero())), one());
/// ```
pub fn succ() -> Term { abs(abs(abs(Var(2).app(Var(3).app(Var(2)).app(Var(1)))))) }

/// Applied to two Church-encoded numbers it produces their sum.
///
/// PLUS := λmnfx.m f (n f x) = λ λ λ λ 4 2 (3 2 1)
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{zero, one, plus};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(plus().app(zero()).app(one())), one());
/// ```
pub fn plus() -> Term { abs(abs(abs(abs(Var(4).app(Var(2)).app(Var(3).app(Var(2)).app(Var(1))))))) }

/// Applied to two Church-encoded numbers it produces their product.
///
/// MULT := λmnf.m (n f) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{one, mult};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(mult().app(one()).app(one())), one());
/// ```
pub fn mult() -> Term { abs(abs(abs(Var(3).app(Var(2).app(Var(1)))))) }

/// Applied to two Church-encoded numbers it raises the first one to the power of the second one.
///
/// POW := λbe.e b = λ λ 1 2
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{one, pow};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(pow().app(one()).app(one())), one());
/// ```
pub fn pow() -> Term { abs(abs(Var(1).app(Var(2)))) }

/// Applied to a Church-encoded number it produces its predecessor.
///
/// PRED := λnfx.n (λgh.h (g f)) (λu.x) (λu.u) = λ λ λ 3 (λ λ 1 (2 4)) (λ 2) (λ 1)
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{zero, one, pred};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(pred().app(one())), zero());
/// ```
pub fn pred() -> Term { abs(abs(abs(Var(3).app(abs(abs(Var(1).app(Var(2).app(Var(4)))))).app(abs(Var(2))).app(abs(Var(1)))))) }

/// Applied to two Church-encoded numbers it subtracts the second one from the first one.
///
/// SUB := λmn.n PRED m = λ λ 1 PRED 2
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{zero, one, sub};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(sub().app(one()).app(zero())), one());
/// ```
pub fn sub() -> Term { abs(abs(Var(1).app(pred()).app(Var(2)))) }

/// Applied to two Church-encoded numbers it returns a Church-encoded boolean indicating whether its
/// first argument is less than the second one.
///
/// LT := λab.NOT (LEQ b a) = λ λ NOT (LEQ 1 2)
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{zero, one, lt};
/// use lambda_calculus::booleans::tru;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(lt().app(zero()).app(one())), tru());
/// ```
pub fn lt() -> Term { abs(abs(not().app(leq().app(Var(1)).app(Var(2))))) }

/// Applied to two Church-encoded numbers it returns a Church-encoded boolean indicating whether its
/// first argument is less or egual to the second one.
///
/// LEQ := λmn.IS_ZERO (SUB m n) = λ λ IS_ZERO (SUB 2 1)
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{zero, one, leq};
/// use lambda_calculus::booleans::tru;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(leq().app(zero()).app(one())), tru());
/// ```
pub fn leq() -> Term { abs(abs(is_zero().app(sub().app(Var(2)).app(Var(1))))) }

/// Applied to two Church-encoded numbers it returns a Church-encoded boolean indicating whether its
/// first argument is egual to the second one.
///
/// EQ := λmn.AND (LEQ m n) (LEQ n m) = λ λ AND (LEQ 2 1) (LEQ 1 2)
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{one, eq};
/// use lambda_calculus::booleans::tru;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(eq().app(one()).app(one())), tru());
/// ```
pub fn eq() -> Term { abs(abs(and().app(leq().app(Var(2)).app(Var(1))).app(leq().app(Var(1)).app(Var(2))))) }

impl Term {
	/// Returns the value of a Church-encoded number.
	///
	/// # Example
	/// ```
	/// use lambda_calculus::arithmetic::one;
	///
	/// assert_eq!(one().value(), Ok(1));
	/// ```
	pub fn value(&self) -> Result<usize, Error> {
		if let Ok(ref inner) = self.unabs_ref().and_then(|t| t.unabs_ref()) {
			Ok(try!(inner._value()))
		} else {
			Err(NotANum)
		}
	}

	fn _value(&self) -> Result<usize, Error> {
		if let Ok(ref rhs) = self.rhs_ref() {
			Ok(1 + try!(rhs._value()))
		} else if let Var(n) = *self {
			if n == 1 {
				Ok(0)
			} else {
				Err(NotANum)
			}
		} else {
			Err(NotANum)
		}
	}

	/// Checks whether a term is a Church-encoded number.
	///
	/// # Example
	/// ```
	/// use lambda_calculus::arithmetic::one;
	///
	/// assert!(one().is_number());
	/// ```
	pub fn is_number(&self) -> bool { self.value().is_ok() }
}

/// Produces a Church-encoded term with a value of the given natural number.
///
/// # Example
/// ```
/// use lambda_calculus::arithmetic::{one, to_cnum};
///
/// assert_eq!(to_cnum(1), one());
/// ```
pub fn to_cnum(n: usize) -> Term {
	let mut inner = Var(1);
	let mut count = n;

	while count > 0 {
		inner = Var(2).app(inner);
		count -= 1;
	}

	abs(abs(inner))
}

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

	#[test]
	fn church_zero() {
		assert_eq!(normalize(is_zero().app(zero())), tru());
		assert_eq!(normalize(is_zero().app(one())), fls());
	}

	#[test]
	fn church_successor() {
		assert_eq!(normalize(succ().app(zero())), one());
		assert_eq!(normalize(succ().app(one())), abs(abs(Var(2).app(Var(2).app(Var(1))))));
		assert_eq!(normalize(succ().app(succ().app(succ().app(zero())))), abs(abs(Var(2).app(Var(2).app(Var(2).app(Var(1)))))));
	}

	#[test]
	fn church_number_identification() {
		for n in 0..5 { assert!(to_cnum(n).is_number()) }
	}

	#[test]
	fn church_number_creation() {
		assert_eq!(to_cnum(0), zero());
		assert_eq!(to_cnum(1), one());
		assert_eq!(to_cnum(2), normalize(succ().app(one())));
	}

	#[test]
	fn church_number_values() {
		for n in 0..10 { assert_eq!(to_cnum(n).value(), Ok(n)) }

		assert_eq!(tru().value(),		Err(NotANum));
		assert_eq!(Var(1).value(),		Err(NotANum));
		assert_eq!(abs(Var(1)).value(),	Err(NotANum));
	}

	#[test]
	fn church_addition() {
		assert_eq!(normalize(plus().app(one())), succ()); // PLUS 1 → SUCC

		assert_eq!(normalize(plus().app(zero()).app(zero())), zero());
		assert_eq!(normalize(plus().app(zero()).app(one())),  one());
		assert_eq!(normalize(plus().app(one()).app(zero())),  one());
		assert_eq!(normalize(plus().app(one()).app(one())),   to_cnum(2));

		assert_eq!(normalize(plus().app(to_cnum(2)).app(to_cnum(3))), to_cnum(5));
		assert_eq!(normalize(plus().app(to_cnum(4)).app(to_cnum(4))), to_cnum(8));
	}

	#[test]
	fn church_multiplication() {
		assert_eq!(normalize(mult().app(to_cnum(3)).app(to_cnum(4))), to_cnum(12));
		assert_eq!(normalize(mult().app(to_cnum(1)).app(to_cnum(3))), to_cnum(3));
		assert_eq!(normalize(mult().app(to_cnum(5)).app(to_cnum(0))), to_cnum(0));
	}

	#[test]
	fn church_exponentiation() {
		assert_eq!(normalize(pow().app(to_cnum(2)).app(to_cnum(4))), to_cnum(16));
		assert_eq!(normalize(pow().app(to_cnum(1)).app(to_cnum(6))), to_cnum(1));
		assert_eq!(normalize(pow().app(to_cnum(3)).app(to_cnum(2))), to_cnum(9));
		assert_eq!(normalize(pow().app(to_cnum(4)).app(to_cnum(1))), to_cnum(4));
//		assert_eq!(normalize(pow().app(to_cnum(5)).app(zero())),	 to_cnum(1)); // n^0 fails - why?
	}

	#[test]
	fn church_subtraction() {
		assert_eq!(normalize(sub().app(zero()).app(zero())),	zero());
		assert_eq!(normalize(sub().app(zero()).app(one())),		zero());
		assert_eq!(normalize(sub().app(one()).app(zero())),		one());
		assert_eq!(normalize(sub().app(to_cnum(2)).app(one())), one());

		assert_eq!(normalize(sub().app(to_cnum(5)).app(to_cnum(3))), to_cnum(2));
		assert_eq!(normalize(sub().app(to_cnum(8)).app(to_cnum(4))), to_cnum(4));
	}

	#[test]
	fn church_predecessor() {
		assert_eq!(normalize(pred().app(zero())), zero());
		assert_eq!(normalize(pred().app(one())), zero());
		assert_eq!(normalize(pred().app(to_cnum(5))), to_cnum(4));
	}

	#[test]
	fn church_comparison() {
		assert_eq!(normalize(lt().app(zero()).app(zero())), fls());
		assert_eq!(normalize(lt().app(one()).app(zero())),  fls());
		assert_eq!(normalize(lt().app(zero()).app(one())),  tru());

		assert_eq!(normalize(leq().app(zero()).app(zero())), tru());
		assert_eq!(normalize(leq().app(zero()).app(one())),  tru());
		assert_eq!(normalize(leq().app(one()).app(zero())),  fls());

		assert_eq!(normalize(eq().app(zero()).app(zero())), tru());
		assert_eq!(normalize(eq().app(zero()).app(one())),  fls());
		assert_eq!(normalize(eq().app(one()).app(zero())),  fls());
		// TODO: add lt, gt, geq
	}
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::hash::BuildHasherDefault;

use fnv::FnvHasher;

use {Entity, Index, Generation};
use bitset::BitSet;

/// Base trait for a component storage that is used as a trait object.
/// Doesn't depent on the actual component type.
pub trait StorageBase {
    /// Delete a particular entity from the storage.
    fn del(&mut self, Entity);
}

/// Typed component storage trait.
pub trait Storage<T>: StorageBase + Sized {
    /// Used during iterator
    type UnprotectedStorage: UnprotectedStorage<T>;

    /// Create a new storage. This is called when you register a new
    /// component type within the world.
    fn new() -> Self;
    /// Insert a new data for a given entity.
    fn insert(&mut self, Entity, T);
    /// Try reading the data associated with an entity.
    fn get(&self, Entity) -> Option<&T>;
    /// Try mutating the data associated with an entity.
    fn get_mut(&mut self, Entity) -> Option<&mut T>;
    /// Remove the data associated with an entity.
    fn remove(&mut self, Entity) -> Option<T>;
    /// splits the bitset from the storage for use
    /// by the join iterator.
    fn open(&self) -> (&BitSet, &Self::UnprotectedStorage);
    /// splits the bitset from the storage for use
    /// by the join iterator.
    fn open_mut(&mut self) -> (&BitSet, &mut Self::UnprotectedStorage);
}

/// Used by the framework to quickly join componets
pub trait UnprotectedStorage<T> {
    /// Try reading the data associated with an entity.
    /// this is unsafe because the external set used
    /// to protect this storage is absent
    unsafe fn get(&self, id: Index) -> &T;
    /// Try mutating the data associated with an entity.
    /// this is unsafe because the external set used
    /// to protect this storage is absent
    unsafe fn get_mut(&mut self, id: Index) -> &mut T;
}

pub struct InnerHashMap<T>(HashMap<Index, GenerationData<T>, BuildHasherDefault<FnvHasher>>);

/// HashMap-based storage. Best suited for rare components.
pub struct HashMapStorage<T>{
    set: BitSet,
    map: InnerHashMap<T>
}

impl<T> StorageBase for HashMapStorage<T> {
    fn del(&mut self, entity: Entity) {
        if self.set.remove(entity.get_id() as u32) {
            self.map.0.remove(&(entity.get_id() as u32));
        }
    }
}

impl<T> Storage<T> for HashMapStorage<T> {
    type UnprotectedStorage = InnerHashMap<T>;

    fn new() -> Self {
        let fnv = BuildHasherDefault::<FnvHasher>::default();
        HashMapStorage {
            set: BitSet::new(),
            map: InnerHashMap(HashMap::with_hasher(fnv))
        }
    }
    fn get(&self, entity: Entity) -> Option<&T> {
        self.map.0.get(&(entity.get_id() as u32))
            .and_then(|x| if x.generation == entity.get_gen() { Some(&x.data) } else { None })

    }
    fn get_mut(&mut self, entity: Entity) -> Option<&mut T> {
        self.map.0.get_mut(&(entity.get_id() as u32))
            .and_then(|x| if x.generation == entity.get_gen() { Some(&mut x.data) } else { None })

    }
    fn insert(&mut self, entity: Entity, value: T) {
        let value = GenerationData{
            data: value,
            generation: entity.get_gen()
        };
        if self.map.0.insert(entity.get_id() as u32, value).is_none() {
            self.set.add(entity.get_id() as u32);
        }
    }
    fn remove(&mut self, entity: Entity) -> Option<T> {
        if self.set.remove(entity.get_id() as u32) {
            let value = self.map.0.remove(&(entity.get_id() as u32)).unwrap();
            if value.generation == entity.get_gen() {
                Some(value.data)
            } else {
                // it should be unlikely that the generation mismatch was
                // wrong, so this is a slow path to re-add the value back
                self.insert(entity, value.data);
                None
            }
        } else {
            None
        }
    }
    fn open(&self) -> (&BitSet, &Self::UnprotectedStorage) {
        (&self.set, &self.map)
    }
    fn open_mut(&mut self) -> (&BitSet, &mut Self::UnprotectedStorage) {
        (&self.set, &mut self.map)
    }
}

impl<T> UnprotectedStorage<T> for InnerHashMap<T> {
    unsafe fn get(&self, e: Index) -> &T {
        &self.0.get(&e).unwrap().data
    }
    unsafe fn get_mut(&mut self, e: Index) -> &mut T {
        &mut self.0.get_mut(&e).unwrap().data
    }
}

pub struct InnerVec<T>(Vec<GenerationData<T>>);

pub struct GenerationData<T> {
    pub generation: Generation,
    pub data: T
}

/// Vec-based storage, actually wraps data into options and stores the generations
/// of the data in order to match with given entities. Supposed to have maximum
/// performance for the components mostly present in entities.
pub struct VecStorage<T> {
    set: BitSet,
    values: InnerVec<T>,
}

impl<T> VecStorage<T> {
    fn extend(&mut self, id: usize) {
        debug_assert!(id >= self.values.0.len());
        let delta = (id + 1) - self.values.0.len();
        self.values.0.reserve(delta);
        unsafe {
            self.values.0.set_len(id + 1);
        }
    }
}

impl<T> Drop for VecStorage<T> {
    fn drop(&mut self) {
        use std::mem;

        for (i, v) in self.values.0.drain(..).enumerate() {
            // if v was not in the set the data is invalid
            // and we must forget it instead of dropping it
            if !self.set.remove(i as u32) {
                mem::forget(v);
            }
        }
    }
}

impl<T> super::StorageBase for VecStorage<T> {
    fn del(&mut self, e: Entity) {
        self.remove(e);
    }
}

impl<T> super::Storage<T> for VecStorage<T> {
    type UnprotectedStorage = InnerVec<T>;

    fn new() -> Self {
        VecStorage {
            set: BitSet::new(),
            values: InnerVec(Vec::new()),
        }
    }
    fn get(&self, e: Entity) -> Option<&T> {
        let id = e.get_id();
        if self.set.contains(id as u32) {
            let v = unsafe { self.values.0.get_unchecked(id) };
            if v.generation == e.get_gen() {
                return Some(&v.data);
            }
        }
        None

    }
    fn get_mut(&mut self, e: Entity) -> Option<&mut T> {
        let id = e.get_id();
        if self.set.contains(id as u32) {
            let v = unsafe { self.values.0.get_unchecked_mut(id) };
            if v.generation == e.get_gen() {
                return Some(&mut v.data);
            }
        }
        None
    }
    fn insert(&mut self, e: Entity, mut v: T) {
        use std::{ptr, mem};

        let id = e.get_id();
        if self.set.contains(id as u32) {
            let mut data = &mut self.values.0[id];
            data.generation = e.get_gen();
            mem::swap(&mut data.data, &mut v);
            Some(v)
        } else {
            self.set.add(id as u32);
            if self.values.0.len() <= id {
                self.extend(id);
            }
            unsafe {
                ptr::write(
                    &mut self.values.0[id],
                    GenerationData{
                        generation: e.get_gen(),
                        data: v
                    }
                );
            }
            None
        };
    }
    fn remove(&mut self, e: Entity) -> Option<T> {
        use std::ptr;

        let (id, gen) = (e.get_id(), e.get_gen());
        let gen_matches = self.values.0.get(id)
            .map(|x| x.generation == gen).unwrap_or(false);

        if gen_matches && self.set.remove(id as u32) {
            let value = unsafe { ptr::read(&self.values.0[id]) };
            Some(value.data)
        } else {
            None
        }
    }
    fn open(&self) -> (&BitSet, &InnerVec<T>) {
        (&self.set, &self.values)
    }
    fn open_mut(&mut self) -> (&BitSet, &mut InnerVec<T>) {
        (&self.set, &mut self.values)
    }
}

impl<T> super::UnprotectedStorage<T> for InnerVec<T> {
    unsafe fn get(&self, e: u32) -> &T {
        &self.0.get_unchecked(e as usize).data
    }
    unsafe fn get_mut(&mut self, e: u32) -> &mut T {
        &mut self.0.get_unchecked_mut(e as usize).data
    }
}

#[cfg(test)]
mod map_test {
    use {Storage, Entity, Generation};
    use super::VecStorage;

    #[test]
    fn insert() {
        let mut c = VecStorage::new();
        for i in 0..1_000 {
            c.insert(Entity::new(i, Generation(0)), i);
        }

        for i in 0..1_000 {
            assert_eq!(c.get(Entity::new(i, Generation(0))).unwrap(), &i);
        }
    }

    #[test]
    fn insert_100k() {
        let mut c = VecStorage::new();
        for i in 0..100_000 {
            c.insert(Entity::new(i, Generation(0)), i);
        }

        for i in 0..100_000 {
            assert_eq!(c.get(Entity::new(i, Generation(0))).unwrap(), &i);
        }
    }

    #[test]
    fn remove() {
        let mut c = VecStorage::new();
        for i in 0..1_000 {
            c.insert(Entity::new(i, Generation(0)), i);
        }

        for i in 0..1_000 {
            assert_eq!(c.get(Entity::new(i, Generation(0))).unwrap(), &i);
        }

        for i in 0..1_000 {
            c.remove(Entity::new(i, Generation(0)));
        }

        for i in 0..1_000 {
            assert!(c.get(Entity::new(i, Generation(0))).is_none());
        }
    }

    #[test]
    fn test_gen() {
        let mut c = VecStorage::new();
        for i in 0..1_000i32 {
            c.insert(Entity::new(i as u32, Generation(0)), i);
            c.insert(Entity::new(i as u32, Generation(0)), -i);
        }

        for i in 0..1_000i32 {
            assert_eq!(c.get(Entity::new(i as u32, Generation(0))).unwrap(), &-i);
        }
    }

    #[test]
    fn insert_same_key() {
        let mut c = VecStorage::new();
        for i in 0..10_000 {
            c.insert(Entity::new(i as u32, Generation(0)), i);
            assert_eq!(c.get(Entity::new(i as u32, Generation(0))).unwrap(), &i);
        }
    }

    #[should_panic]
    #[test]
    fn wrap() {
        let mut c = VecStorage::new();
        c.insert(Entity::new(1 << 21, Generation(0)), 7);
    }
}

#[cfg(test)]
mod test {
    use {Entity, Generation, Storage, VecStorage, HashMapStorage};

    fn test_add<S>() where S: Storage<u32> {
        let mut s = S::new();
        for i in 0..1_000 {
            s.insert(Entity::new(i, Generation(1)), i + 2718);
        }

        for i in 0..1_000 {
            assert_eq!(*s.get(Entity::new(i, Generation(1))).unwrap(), i + 2718);
        }
    }

    fn test_sub<S>() where S: Storage<u32> {
        let mut s = S::new();
        for i in 0..1_000 {
            s.insert(Entity::new(i, Generation(1)), i + 2718);
        }

        for i in 0..1_000 {
            assert_eq!(s.remove(Entity::new(i, Generation(1))).unwrap(), i + 2718);
            assert!(s.remove(Entity::new(i, Generation(1))).is_none());
        }
    }

    fn test_get_mut<S>() where S: Storage<u32> {
        let mut s = S::new();
        for i in 0..1_000 {
            s.insert(Entity::new(i, Generation(1)), i + 2718);
        }

        for i in 0..1_000 {
            *s.get_mut(Entity::new(i, Generation(1))).unwrap() -= 718;
        }

        for i in 0..1_000 {
            assert_eq!(*s.get(Entity::new(i, Generation(1))).unwrap(), i + 2000);
        }
    }

    fn test_add_gen<S>() where S: Storage<u32> {
        let mut s = S::new();
        for i in 0..1_000 {
            s.insert(Entity::new(i, Generation(1)), i + 2718);
            s.insert(Entity::new(i, Generation(2)), i + 31415);
        }

        for i in 0..1_000 {
            // this is removed since vec and hashmap disagree
            // on how this behavior should work...
            //assert!(s.get(Entity::new(i, 1)).is_none());
            assert_eq!(*s.get(Entity::new(i, Generation(2))).unwrap(), i + 31415);
        }
    }

    fn test_sub_gen<S>() where S: Storage<u32> {
        let mut s = S::new();
        for i in 0..1_000 {
            s.insert(Entity::new(i, Generation(2)), i + 2718);
        }

        for i in 0..1_000 {
            assert!(s.remove(Entity::new(i, Generation(1))).is_none());
        }
    }

    #[test] fn vec_test_add() { test_add::<VecStorage<u32>>(); }
    #[test] fn vec_test_sub() { test_sub::<VecStorage<u32>>(); }
    #[test] fn vec_test_get_mut() { test_get_mut::<VecStorage<u32>>(); }
    #[test] fn vec_test_add_gen() { test_add_gen::<VecStorage<u32>>(); }
    #[test] fn vec_test_sub_gen() { test_sub_gen::<VecStorage<u32>>(); }

    #[test] fn hash_test_add() { test_add::<HashMapStorage<u32>>(); }
    #[test] fn hash_test_sub() { test_sub::<HashMapStorage<u32>>(); }
    #[test] fn hash_test_get_mut() { test_get_mut::<HashMapStorage<u32>>(); }
    #[test] fn hash_test_add_gen() { test_add_gen::<HashMapStorage<u32>>(); }
    #[test] fn hash_test_sub_gen() { test_sub_gen::<HashMapStorage<u32>>(); }
}

<commit_msg>cleanup doc comments in storage.rs<commit_after>use std::collections::HashMap;
use std::hash::BuildHasherDefault;

use fnv::FnvHasher;

use {Entity, Index, Generation};
use bitset::BitSet;

/// Base trait for a component storage that is used as a trait object.
/// Doesn't depend on the actual component type.
pub trait StorageBase {
    /// Deletes a particular `Entity` from the storage.
    fn del(&mut self, Entity);
}

/// Typed component storage trait.
pub trait Storage<T>: StorageBase + Sized {
    /// Used during iterator
    type UnprotectedStorage: UnprotectedStorage<T>;

    /// Creates a new `Storage<T>`. This is called when you register a new
    /// component type within the world.
    fn new() -> Self;
    /// Inserts new data for a given `Entity`.
    fn insert(&mut self, Entity, T);
    /// Tries to read the data associated with an `Entity`.
    fn get(&self, Entity) -> Option<&T>;
    /// Tries to mutate the data associated with an `Entity`.
    fn get_mut(&mut self, Entity) -> Option<&mut T>;
    /// Removes the data associated with an `Entity`.
    fn remove(&mut self, Entity) -> Option<T>;
    /// Splits the `BitSet` from the storage for use
    /// by the `Join` iterator.
    fn open(&self) -> (&BitSet, &Self::UnprotectedStorage);
    /// Splits the `BitSet` mutably from the storage for use
    /// by the `Join` iterator.
    fn open_mut(&mut self) -> (&BitSet, &mut Self::UnprotectedStorage);
}

/// Used by the framework to quickly join componets
pub trait UnprotectedStorage<T> {
    /// Tries reading the data associated with an `Entity`.
    /// This is unsafe because the external set used
    /// to protect this storage is absent.
    unsafe fn get(&self, id: Index) -> &T;
    /// Tries mutating the data associated with an `Entity`.
    /// This is unsafe because the external set used
    /// to protect this storage is absent.
    unsafe fn get_mut(&mut self, id: Index) -> &mut T;
}

pub struct InnerHashMap<T>(HashMap<Index, GenerationData<T>, BuildHasherDefault<FnvHasher>>);

/// HashMap-based storage. Best suited for rare components.
pub struct HashMapStorage<T>{
    set: BitSet,
    map: InnerHashMap<T>
}

impl<T> StorageBase for HashMapStorage<T> {
    fn del(&mut self, entity: Entity) {
        if self.set.remove(entity.get_id() as u32) {
            self.map.0.remove(&(entity.get_id() as u32));
        }
    }
}

impl<T> Storage<T> for HashMapStorage<T> {
    type UnprotectedStorage = InnerHashMap<T>;

    fn new() -> Self {
        let fnv = BuildHasherDefault::<FnvHasher>::default();
        HashMapStorage {
            set: BitSet::new(),
            map: InnerHashMap(HashMap::with_hasher(fnv))
        }
    }
    fn get(&self, entity: Entity) -> Option<&T> {
        self.map.0.get(&(entity.get_id() as u32))
            .and_then(|x| if x.generation == entity.get_gen() { Some(&x.data) } else { None })

    }
    fn get_mut(&mut self, entity: Entity) -> Option<&mut T> {
        self.map.0.get_mut(&(entity.get_id() as u32))
            .and_then(|x| if x.generation == entity.get_gen() { Some(&mut x.data) } else { None })

    }
    fn insert(&mut self, entity: Entity, value: T) {
        let value = GenerationData{
            data: value,
            generation: entity.get_gen()
        };
        if self.map.0.insert(entity.get_id() as u32, value).is_none() {
            self.set.add(entity.get_id() as u32);
        }
    }
    fn remove(&mut self, entity: Entity) -> Option<T> {
        if self.set.remove(entity.get_id() as u32) {
            let value = self.map.0.remove(&(entity.get_id() as u32)).unwrap();
            if value.generation == entity.get_gen() {
                Some(value.data)
            } else {
                // it should be unlikely that the generation mismatch was
                // wrong, so this is a slow path to re-add the value back
                self.insert(entity, value.data);
                None
            }
        } else {
            None
        }
    }
    fn open(&self) -> (&BitSet, &Self::UnprotectedStorage) {
        (&self.set, &self.map)
    }
    fn open_mut(&mut self) -> (&BitSet, &mut Self::UnprotectedStorage) {
        (&self.set, &mut self.map)
    }
}

impl<T> UnprotectedStorage<T> for InnerHashMap<T> {
    unsafe fn get(&self, e: Index) -> &T {
        &self.0.get(&e).unwrap().data
    }
    unsafe fn get_mut(&mut self, e: Index) -> &mut T {
        &mut self.0.get_mut(&e).unwrap().data
    }
}

pub struct InnerVec<T>(Vec<GenerationData<T>>);

pub struct GenerationData<T> {
    pub generation: Generation,
    pub data: T
}

/// Vec-based storage, stores the generations of the data in
/// order to match with given entities. Supposed to have maximum
/// performance for the components mostly present in entities.
pub struct VecStorage<T> {
    set: BitSet,
    values: InnerVec<T>,
}

impl<T> VecStorage<T> {
    fn extend(&mut self, id: usize) {
        debug_assert!(id >= self.values.0.len());
        let delta = (id + 1) - self.values.0.len();
        self.values.0.reserve(delta);
        unsafe {
            self.values.0.set_len(id + 1);
        }
    }
}

impl<T> Drop for VecStorage<T> {
    fn drop(&mut self) {
        use std::mem;

        for (i, v) in self.values.0.drain(..).enumerate() {
            // if v was not in the set the data is invalid
            // and we must forget it instead of dropping it
            if !self.set.remove(i as u32) {
                mem::forget(v);
            }
        }
    }
}

impl<T> super::StorageBase for VecStorage<T> {
    fn del(&mut self, e: Entity) {
        self.remove(e);
    }
}

impl<T> super::Storage<T> for VecStorage<T> {
    type UnprotectedStorage = InnerVec<T>;

    fn new() -> Self {
        VecStorage {
            set: BitSet::new(),
            values: InnerVec(Vec::new()),
        }
    }
    fn get(&self, e: Entity) -> Option<&T> {
        let id = e.get_id();
        if self.set.contains(id as u32) {
            let v = unsafe { self.values.0.get_unchecked(id) };
            if v.generation == e.get_gen() {
                return Some(&v.data);
            }
        }
        None

    }
    fn get_mut(&mut self, e: Entity) -> Option<&mut T> {
        let id = e.get_id();
        if self.set.contains(id as u32) {
            let v = unsafe { self.values.0.get_unchecked_mut(id) };
            if v.generation == e.get_gen() {
                return Some(&mut v.data);
            }
        }
        None
    }
    fn insert(&mut self, e: Entity, mut v: T) {
        use std::{ptr, mem};

        let id = e.get_id();
        if self.set.contains(id as u32) {
            let mut data = &mut self.values.0[id];
            data.generation = e.get_gen();
            mem::swap(&mut data.data, &mut v);
            Some(v)
        } else {
            self.set.add(id as u32);
            if self.values.0.len() <= id {
                self.extend(id);
            }
            unsafe {
                ptr::write(
                    &mut self.values.0[id],
                    GenerationData{
                        generation: e.get_gen(),
                        data: v
                    }
                );
            }
            None
        };
    }
    fn remove(&mut self, e: Entity) -> Option<T> {
        use std::ptr;

        let (id, gen) = (e.get_id(), e.get_gen());
        let gen_matches = self.values.0.get(id)
            .map(|x| x.generation == gen).unwrap_or(false);

        if gen_matches && self.set.remove(id as u32) {
            let value = unsafe { ptr::read(&self.values.0[id]) };
            Some(value.data)
        } else {
            None
        }
    }
    fn open(&self) -> (&BitSet, &InnerVec<T>) {
        (&self.set, &self.values)
    }
    fn open_mut(&mut self) -> (&BitSet, &mut InnerVec<T>) {
        (&self.set, &mut self.values)
    }
}

impl<T> super::UnprotectedStorage<T> for InnerVec<T> {
    unsafe fn get(&self, e: u32) -> &T {
        &self.0.get_unchecked(e as usize).data
    }
    unsafe fn get_mut(&mut self, e: u32) -> &mut T {
        &mut self.0.get_unchecked_mut(e as usize).data
    }
}

#[cfg(test)]
mod map_test {
    use {Storage, Entity, Generation};
    use super::VecStorage;

    #[test]
    fn insert() {
        let mut c = VecStorage::new();
        for i in 0..1_000 {
            c.insert(Entity::new(i, Generation(0)), i);
        }

        for i in 0..1_000 {
            assert_eq!(c.get(Entity::new(i, Generation(0))).unwrap(), &i);
        }
    }

    #[test]
    fn insert_100k() {
        let mut c = VecStorage::new();
        for i in 0..100_000 {
            c.insert(Entity::new(i, Generation(0)), i);
        }

        for i in 0..100_000 {
            assert_eq!(c.get(Entity::new(i, Generation(0))).unwrap(), &i);
        }
    }

    #[test]
    fn remove() {
        let mut c = VecStorage::new();
        for i in 0..1_000 {
            c.insert(Entity::new(i, Generation(0)), i);
        }

        for i in 0..1_000 {
            assert_eq!(c.get(Entity::new(i, Generation(0))).unwrap(), &i);
        }

        for i in 0..1_000 {
            c.remove(Entity::new(i, Generation(0)));
        }

        for i in 0..1_000 {
            assert!(c.get(Entity::new(i, Generation(0))).is_none());
        }
    }

    #[test]
    fn test_gen() {
        let mut c = VecStorage::new();
        for i in 0..1_000i32 {
            c.insert(Entity::new(i as u32, Generation(0)), i);
            c.insert(Entity::new(i as u32, Generation(0)), -i);
        }

        for i in 0..1_000i32 {
            assert_eq!(c.get(Entity::new(i as u32, Generation(0))).unwrap(), &-i);
        }
    }

    #[test]
    fn insert_same_key() {
        let mut c = VecStorage::new();
        for i in 0..10_000 {
            c.insert(Entity::new(i as u32, Generation(0)), i);
            assert_eq!(c.get(Entity::new(i as u32, Generation(0))).unwrap(), &i);
        }
    }

    #[should_panic]
    #[test]
    fn wrap() {
        let mut c = VecStorage::new();
        c.insert(Entity::new(1 << 21, Generation(0)), 7);
    }
}

#[cfg(test)]
mod test {
    use {Entity, Generation, Storage, VecStorage, HashMapStorage};

    fn test_add<S>() where S: Storage<u32> {
        let mut s = S::new();
        for i in 0..1_000 {
            s.insert(Entity::new(i, Generation(1)), i + 2718);
        }

        for i in 0..1_000 {
            assert_eq!(*s.get(Entity::new(i, Generation(1))).unwrap(), i + 2718);
        }
    }

    fn test_sub<S>() where S: Storage<u32> {
        let mut s = S::new();
        for i in 0..1_000 {
            s.insert(Entity::new(i, Generation(1)), i + 2718);
        }

        for i in 0..1_000 {
            assert_eq!(s.remove(Entity::new(i, Generation(1))).unwrap(), i + 2718);
            assert!(s.remove(Entity::new(i, Generation(1))).is_none());
        }
    }

    fn test_get_mut<S>() where S: Storage<u32> {
        let mut s = S::new();
        for i in 0..1_000 {
            s.insert(Entity::new(i, Generation(1)), i + 2718);
        }

        for i in 0..1_000 {
            *s.get_mut(Entity::new(i, Generation(1))).unwrap() -= 718;
        }

        for i in 0..1_000 {
            assert_eq!(*s.get(Entity::new(i, Generation(1))).unwrap(), i + 2000);
        }
    }

    fn test_add_gen<S>() where S: Storage<u32> {
        let mut s = S::new();
        for i in 0..1_000 {
            s.insert(Entity::new(i, Generation(1)), i + 2718);
            s.insert(Entity::new(i, Generation(2)), i + 31415);
        }

        for i in 0..1_000 {
            // this is removed since vec and hashmap disagree
            // on how this behavior should work...
            //assert!(s.get(Entity::new(i, 1)).is_none());
            assert_eq!(*s.get(Entity::new(i, Generation(2))).unwrap(), i + 31415);
        }
    }

    fn test_sub_gen<S>() where S: Storage<u32> {
        let mut s = S::new();
        for i in 0..1_000 {
            s.insert(Entity::new(i, Generation(2)), i + 2718);
        }

        for i in 0..1_000 {
            assert!(s.remove(Entity::new(i, Generation(1))).is_none());
        }
    }

    #[test] fn vec_test_add() { test_add::<VecStorage<u32>>(); }
    #[test] fn vec_test_sub() { test_sub::<VecStorage<u32>>(); }
    #[test] fn vec_test_get_mut() { test_get_mut::<VecStorage<u32>>(); }
    #[test] fn vec_test_add_gen() { test_add_gen::<VecStorage<u32>>(); }
    #[test] fn vec_test_sub_gen() { test_sub_gen::<VecStorage<u32>>(); }

    #[test] fn hash_test_add() { test_add::<HashMapStorage<u32>>(); }
    #[test] fn hash_test_sub() { test_sub::<HashMapStorage<u32>>(); }
    #[test] fn hash_test_get_mut() { test_get_mut::<HashMapStorage<u32>>(); }
    #[test] fn hash_test_add_gen() { test_add_gen::<HashMapStorage<u32>>(); }
    #[test] fn hash_test_sub_gen() { test_sub_gen::<HashMapStorage<u32>>(); }
}

<|endoftext|>


<commit_before>// partially (c) 2016 Google Inc. (Lewin Bormann, lewinb@google.com)
//
// See project root for licensing information.
//
use crate::types::Token;

use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::io;
use std::path::{Path, PathBuf};
use std::sync::Mutex;

use serde::{Deserialize, Serialize};

#[derive(Debug)]
pub struct HashedScopes<'a, T> {
    hash: u64,
    scopes: &'a [T],
}

// Implement Clone manually. Auto derive fails to work correctly because we want
// Clone to be implemented regardless of whether T is Clone or not.
impl<'a, T> Clone for HashedScopes<'a, T> {
    fn clone(&self) -> Self {
        HashedScopes {
            hash: self.hash,
            scopes: self.scopes,
        }
    }
}
impl<'a, T> Copy for HashedScopes<'a, T> {}

impl<'a, T> From<&'a [T]> for HashedScopes<'a, T>
where
    T: AsRef<str>,
{
    fn from(scopes: &'a [T]) -> Self {
        // Calculate a hash value describing the scopes. The order of the scopes in the
        // list does not change the hash value. i.e. two lists that contains the exact
        // same scopes, but in different order will return the same hash value.
        let mut hash = DefaultHasher::new().finish();
        for scope in scopes {
            let mut hasher = DefaultHasher::new();
            scope.as_ref().hash(&mut hasher);
            hash ^= hasher.finish();
        }
        HashedScopes { hash, scopes }
    }
}

impl<'a, T> HashedScopes<'a, T>
where
    T: AsRef<str>,
{
    // implement an inherent from method even though From is implemented. This
    // is because passing an array ref like &[&str; 1] (&["foo"]) will be auto
    // deref'd to a slice on function boundaries, but it will not implement the
    // From trait. This inherent method just serves to auto deref from array
    // refs to slices and proxy to the From impl.
    pub fn from(scopes: &'a [T]) -> Self {
        <Self as From<&'a [T]>>::from(scopes)
    }
}

pub(crate) enum Storage {
    Memory { tokens: Mutex<JSONTokens> },
    Disk(DiskStorage),
}

impl Storage {
    pub(crate) async fn set<T>(&self, scopes: HashedScopes<'_, T>, token: Token)
    where
        T: AsRef<str>,
    {
        match self {
            Storage::Memory { tokens } => tokens.lock().unwrap().set(scopes, token),
            Storage::Disk(disk_storage) => disk_storage.set(scopes, token).await,
        }
    }

    pub(crate) fn get<T>(&self, scopes: HashedScopes<T>) -> Option<Token>
    where
        T: AsRef<str>,
    {
        match self {
            Storage::Memory { tokens } => tokens.lock().unwrap().get(scopes),
            Storage::Disk(disk_storage) => disk_storage.get(scopes),
        }
    }
}

/// A single stored token.
#[derive(Debug, Clone, Serialize, Deserialize)]
struct JSONToken {
    pub hash: u64,
    pub scopes: Option<Vec<String>>,
    pub token: Token,
}

impl PartialEq for JSONToken {
    fn eq(&self, other: &Self) -> bool {
        self.hash == other.hash
    }
}

impl Eq for JSONToken {}

impl PartialOrd for JSONToken {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for JSONToken {
    fn cmp(&self, other: &Self) -> Ordering {
        self.hash.cmp(&other.hash)
    }
}

/// List of tokens in a JSON object
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct JSONTokens {
    tokens: Vec<JSONToken>,
}

impl JSONTokens {
    pub(crate) fn new() -> Self {
        JSONTokens { tokens: Vec::new() }
    }

    pub(crate) async fn load_from_file(filename: &Path) -> Result<Self, io::Error> {
        let contents = tokio::fs::read(filename).await?;
        let container: JSONTokens = serde_json::from_slice(&contents)
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
        Ok(container)
    }

    fn get<T>(&self, scopes: HashedScopes<T>) -> Option<Token>
    where
        T: AsRef<str>,
    {
        for t in self.tokens.iter() {
            if let Some(token_scopes) = &t.scopes {
                if scopes
                    .scopes
                    .iter()
                    .all(|s| token_scopes.iter().any(|t| t == s.as_ref()))
                {
                    return Some(t.token.clone());
                }
            } else if scopes.hash == t.hash {
                return Some(t.token.clone());
            }
        }
        None
    }

    fn set<T>(&mut self, scopes: HashedScopes<T>, token: Token)
    where
        T: AsRef<str>,
    {
        eprintln!("setting: {:?}, {:?}", scopes.hash, token);
        self.tokens.retain(|x| x.hash != scopes.hash);

        self.tokens.push(JSONToken {
            hash: scopes.hash,
            scopes: Some(
                scopes
                    .scopes
                    .iter()
                    .map(|x| x.as_ref().to_string())
                    .collect(),
            ),
            token,
        });
    }

    // TODO: ideally this function would accept &Path, but tokio requires the
    // path be 'static. Revisit this and ask why tokio::fs::write has that
    // limitation.
    async fn dump_to_file(&self, path: PathBuf) -> Result<(), io::Error> {
        let serialized = serde_json::to_string(self)
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
        tokio::fs::write(path, &serialized).await
    }
}

pub(crate) struct DiskStorage {
    tokens: Mutex<JSONTokens>,
    write_tx: tokio::sync::mpsc::Sender<JSONTokens>,
}

impl DiskStorage {
    pub(crate) async fn new(path: PathBuf) -> Result<Self, io::Error> {
        let tokens = JSONTokens::load_from_file(&path).await?;
        // Writing to disk will happen in a separate task. This means in the
        // common case returning a token to the user will not be required to
        // wait for disk i/o. We communicate with a dedicated writer task via a
        // buffered channel. This ensures that the writes happen in the order
        // received, and if writes fall too far behind we will block GetToken
        // requests until disk i/o completes.
        let (write_tx, mut write_rx) = tokio::sync::mpsc::channel::<JSONTokens>(2);
        tokio::spawn(async move {
            while let Some(tokens) = write_rx.recv().await {
                if let Err(e) = tokens.dump_to_file(path.to_path_buf()).await {
                    log::error!("Failed to write token storage to disk: {}", e);
                }
            }
        });
        Ok(DiskStorage {
            tokens: Mutex::new(tokens),
            write_tx,
        })
    }

    async fn set<T>(&self, scopes: HashedScopes<'_, T>, token: Token)
    where
        T: AsRef<str>,
    {
        let cloned_tokens = {
            let mut tokens = self.tokens.lock().unwrap();
            tokens.set(scopes, token);
            tokens.clone()
        };
        self.write_tx
            .clone()
            .send(cloned_tokens)
            .await
            .expect("disk storage task not running");
    }

    pub(crate) fn get<T>(&self, scopes: HashedScopes<T>) -> Option<Token>
    where
        T: AsRef<str>,
    {
        self.tokens.lock().unwrap().get(scopes)
    }
}

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

    #[test]
    fn test_hash_scopes() {
        // Idential list should hash equal.
        assert_eq!(
            HashedScopes::from(&["foo", "bar"]).hash,
            HashedScopes::from(&["foo", "bar"]).hash,
        );
        // The hash should be order independent.
        assert_eq!(
            HashedScopes::from(&["bar", "foo"]).hash,
            HashedScopes::from(&["foo", "bar"]).hash,
        );
        assert_eq!(
            HashedScopes::from(&["bar", "baz", "bat"]).hash,
            HashedScopes::from(&["baz", "bar", "bat"]).hash,
        );

        // Ensure hashes differ when the contents are different by more than
        // just order.
        assert_ne!(
            HashedScopes::from(&["foo", "bar", "baz"]).hash,
            HashedScopes::from(&["foo", "bar"]).hash,
        );
    }
}
<commit_msg>JSONToken should always contain scopes.<commit_after>// partially (c) 2016 Google Inc. (Lewin Bormann, lewinb@google.com)
//
// See project root for licensing information.
//
use crate::types::Token;

use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::io;
use std::path::{Path, PathBuf};
use std::sync::Mutex;

use serde::{Deserialize, Serialize};

#[derive(Debug)]
pub struct HashedScopes<'a, T> {
    hash: u64,
    scopes: &'a [T],
}

// Implement Clone manually. Auto derive fails to work correctly because we want
// Clone to be implemented regardless of whether T is Clone or not.
impl<'a, T> Clone for HashedScopes<'a, T> {
    fn clone(&self) -> Self {
        HashedScopes {
            hash: self.hash,
            scopes: self.scopes,
        }
    }
}
impl<'a, T> Copy for HashedScopes<'a, T> {}

impl<'a, T> From<&'a [T]> for HashedScopes<'a, T>
where
    T: AsRef<str>,
{
    fn from(scopes: &'a [T]) -> Self {
        // Calculate a hash value describing the scopes. The order of the scopes in the
        // list does not change the hash value. i.e. two lists that contains the exact
        // same scopes, but in different order will return the same hash value.
        let mut hash = DefaultHasher::new().finish();
        for scope in scopes {
            let mut hasher = DefaultHasher::new();
            scope.as_ref().hash(&mut hasher);
            hash ^= hasher.finish();
        }
        HashedScopes { hash, scopes }
    }
}

impl<'a, T> HashedScopes<'a, T>
where
    T: AsRef<str>,
{
    // implement an inherent from method even though From is implemented. This
    // is because passing an array ref like &[&str; 1] (&["foo"]) will be auto
    // deref'd to a slice on function boundaries, but it will not implement the
    // From trait. This inherent method just serves to auto deref from array
    // refs to slices and proxy to the From impl.
    pub fn from(scopes: &'a [T]) -> Self {
        <Self as From<&'a [T]>>::from(scopes)
    }
}

pub(crate) enum Storage {
    Memory { tokens: Mutex<JSONTokens> },
    Disk(DiskStorage),
}

impl Storage {
    pub(crate) async fn set<T>(&self, scopes: HashedScopes<'_, T>, token: Token)
    where
        T: AsRef<str>,
    {
        match self {
            Storage::Memory { tokens } => tokens.lock().unwrap().set(scopes, token),
            Storage::Disk(disk_storage) => disk_storage.set(scopes, token).await,
        }
    }

    pub(crate) fn get<T>(&self, scopes: HashedScopes<T>) -> Option<Token>
    where
        T: AsRef<str>,
    {
        match self {
            Storage::Memory { tokens } => tokens.lock().unwrap().get(scopes),
            Storage::Disk(disk_storage) => disk_storage.get(scopes),
        }
    }
}

/// A single stored token.
#[derive(Debug, Clone, Serialize, Deserialize)]
struct JSONToken {
    pub hash: u64,
    pub scopes: Vec<String>,
    pub token: Token,
}

impl PartialEq for JSONToken {
    fn eq(&self, other: &Self) -> bool {
        self.hash == other.hash
    }
}

impl Eq for JSONToken {}

impl PartialOrd for JSONToken {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for JSONToken {
    fn cmp(&self, other: &Self) -> Ordering {
        self.hash.cmp(&other.hash)
    }
}

/// List of tokens in a JSON object
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct JSONTokens {
    tokens: Vec<JSONToken>,
}

impl JSONTokens {
    pub(crate) fn new() -> Self {
        JSONTokens { tokens: Vec::new() }
    }

    pub(crate) async fn load_from_file(filename: &Path) -> Result<Self, io::Error> {
        let contents = tokio::fs::read(filename).await?;
        let container: JSONTokens = serde_json::from_slice(&contents)
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
        Ok(container)
    }

    fn get<T>(&self, scopes: HashedScopes<T>) -> Option<Token>
    where
        T: AsRef<str>,
    {
        for t in self.tokens.iter() {
            if scopes
                .scopes
                .iter()
                .all(|s| t.scopes.iter().any(|t| t == s.as_ref()))
            {
                return Some(t.token.clone());
            }
        }
        None
    }

    fn set<T>(&mut self, scopes: HashedScopes<T>, token: Token)
    where
        T: AsRef<str>,
    {
        eprintln!("setting: {:?}, {:?}", scopes.hash, token);
        self.tokens.retain(|x| x.hash != scopes.hash);

        self.tokens.push(JSONToken {
            hash: scopes.hash,
            scopes: scopes
                .scopes
                .iter()
                .map(|x| x.as_ref().to_string())
                .collect(),
            token,
        });
    }

    // TODO: ideally this function would accept &Path, but tokio requires the
    // path be 'static. Revisit this and ask why tokio::fs::write has that
    // limitation.
    async fn dump_to_file(&self, path: PathBuf) -> Result<(), io::Error> {
        let serialized = serde_json::to_string(self)
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
        tokio::fs::write(path, &serialized).await
    }
}

pub(crate) struct DiskStorage {
    tokens: Mutex<JSONTokens>,
    write_tx: tokio::sync::mpsc::Sender<JSONTokens>,
}

impl DiskStorage {
    pub(crate) async fn new(path: PathBuf) -> Result<Self, io::Error> {
        let tokens = JSONTokens::load_from_file(&path).await?;
        // Writing to disk will happen in a separate task. This means in the
        // common case returning a token to the user will not be required to
        // wait for disk i/o. We communicate with a dedicated writer task via a
        // buffered channel. This ensures that the writes happen in the order
        // received, and if writes fall too far behind we will block GetToken
        // requests until disk i/o completes.
        let (write_tx, mut write_rx) = tokio::sync::mpsc::channel::<JSONTokens>(2);
        tokio::spawn(async move {
            while let Some(tokens) = write_rx.recv().await {
                if let Err(e) = tokens.dump_to_file(path.to_path_buf()).await {
                    log::error!("Failed to write token storage to disk: {}", e);
                }
            }
        });
        Ok(DiskStorage {
            tokens: Mutex::new(tokens),
            write_tx,
        })
    }

    async fn set<T>(&self, scopes: HashedScopes<'_, T>, token: Token)
    where
        T: AsRef<str>,
    {
        let cloned_tokens = {
            let mut tokens = self.tokens.lock().unwrap();
            tokens.set(scopes, token);
            tokens.clone()
        };
        self.write_tx
            .clone()
            .send(cloned_tokens)
            .await
            .expect("disk storage task not running");
    }

    pub(crate) fn get<T>(&self, scopes: HashedScopes<T>) -> Option<Token>
    where
        T: AsRef<str>,
    {
        self.tokens.lock().unwrap().get(scopes)
    }
}

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

    #[test]
    fn test_hash_scopes() {
        // Idential list should hash equal.
        assert_eq!(
            HashedScopes::from(&["foo", "bar"]).hash,
            HashedScopes::from(&["foo", "bar"]).hash,
        );
        // The hash should be order independent.
        assert_eq!(
            HashedScopes::from(&["bar", "foo"]).hash,
            HashedScopes::from(&["foo", "bar"]).hash,
        );
        assert_eq!(
            HashedScopes::from(&["bar", "baz", "bat"]).hash,
            HashedScopes::from(&["baz", "bar", "bat"]).hash,
        );

        // Ensure hashes differ when the contents are different by more than
        // just order.
        assert_ne!(
            HashedScopes::from(&["foo", "bar", "baz"]).hash,
            HashedScopes::from(&["foo", "bar"]).hash,
        );
    }
}
<|endoftext|>


<commit_before>//! This LintPass catches both string addition and string addition + assignment
//!
//! Note that since we have two lints where one subsumes the other, we try to
//! disable the subsumed lint unless it has a higher level

use rustc::lint::*;
use rustc::middle::ty::TypeVariants::TyStruct;
use syntax::ast::*;
use syntax::codemap::{Span, Spanned};
use eq_op::is_exp_equal;
use types::match_ty_unwrap;
use utils::{match_def_path, span_lint, walk_ptrs_ty, get_parent_expr};

declare_lint! {
    pub STRING_ADD_ASSIGN,
    Warn,
    "Warn on `x = x + ..` where x is a `String`"
}

declare_lint! {
	pub STRING_ADD,
	Allow,
	"Warn on `x + ..` where x is a `String`"
}

#[derive(Copy, Clone)]
pub struct StringAdd;

impl LintPass for StringAdd {
    fn get_lints(&self) -> LintArray {
        lint_array!(STRING_ADD)
    }

    fn check_expr(&mut self, cx: &Context, e: &Expr) {
		if let &ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) = &e.node {
			if is_string(cx, left) {
				if let Allow = cx.current_level(STRING_ADD_ASSIGN) {
					// the string_add_assign is allow, so no duplicates
				} else {
					let parent = get_parent_expr(cx, e);
					if let Some(ref p) = parent {
						if let &ExprAssign(ref target, _) = &p.node {
							// avoid duplicate matches
							if is_exp_equal(target, left) { return; }
						}
					}
				}
				//TODO check for duplicates
				 span_lint(cx, STRING_ADD, e.span,
						"you add something to a string. \
						Consider using `String::push_str()` instead.")
			}
		}
	}
}

#[derive(Copy, Clone)]
pub struct StringAddAssign;

impl LintPass for StringAddAssign {
    fn get_lints(&self) -> LintArray {
        lint_array!(STRING_ADD_ASSIGN)
    }

    fn check_expr(&mut self, cx: &Context, e: &Expr) {
        if let &ExprAssign(ref target, ref  src) = &e.node {
            if is_string(cx, target) && is_add(src, target) {
                span_lint(cx, STRING_ADD_ASSIGN, e.span,
                    "you assign the result of adding something to this string. \
                    Consider using `String::push_str()` instead")
            }
        }
    }
}

fn is_string(cx: &Context, e: &Expr) -> bool {
	let ty = walk_ptrs_ty(cx.tcx.expr_ty(e));
    if let TyStruct(did, _) = ty.sty {
        match_def_path(cx, did.did, &["collections", "string", "String"])
    } else { false }
}

fn is_add(src: &Expr, target: &Expr) -> bool {
    match &src.node {
        &ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) =>
            is_exp_equal(target, left),
        &ExprBlock(ref block) => block.stmts.is_empty() &&
            block.expr.as_ref().map_or(false, |expr| is_add(&*expr, target)),
        &ExprParen(ref expr) => is_add(&*expr, target),
        _ => false
    }
}
<commit_msg>fixed formatting<commit_after>//! This LintPass catches both string addition and string addition + assignment
//!
//! Note that since we have two lints where one subsumes the other, we try to
//! disable the subsumed lint unless it has a higher level

use rustc::lint::*;
use rustc::middle::ty::TypeVariants::TyStruct;
use syntax::ast::*;
use syntax::codemap::{Span, Spanned};
use eq_op::is_exp_equal;
use types::match_ty_unwrap;
use utils::{match_def_path, span_lint, walk_ptrs_ty, get_parent_expr};

declare_lint! {
    pub STRING_ADD_ASSIGN,
    Warn,
    "Warn on `x = x + ..` where x is a `String`"
}

declare_lint! {
    pub STRING_ADD,
    Allow,
    "Warn on `x + ..` where x is a `String`"
}

#[derive(Copy, Clone)]
pub struct StringAdd;

impl LintPass for StringAdd {
    fn get_lints(&self) -> LintArray {
        lint_array!(STRING_ADD)
    }

    fn check_expr(&mut self, cx: &Context, e: &Expr) {
        if let &ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) = &e.node {
            if is_string(cx, left) {
                if let Allow = cx.current_level(STRING_ADD_ASSIGN) {
                    // the string_add_assign is allow, so no duplicates
                } else {
                    let parent = get_parent_expr(cx, e);
                    if let Some(ref p) = parent {
                        if let &ExprAssign(ref target, _) = &p.node {
                            // avoid duplicate matches
                            if is_exp_equal(target, left) { return; }
                        }
                    }
                }
                //TODO check for duplicates
                 span_lint(cx, STRING_ADD, e.span,
                        "you add something to a string. \
                        Consider using `String::push_str()` instead.")
            }
        }
    }
}

#[derive(Copy, Clone)]
pub struct StringAddAssign;

impl LintPass for StringAddAssign {
    fn get_lints(&self) -> LintArray {
        lint_array!(STRING_ADD_ASSIGN)
    }

    fn check_expr(&mut self, cx: &Context, e: &Expr) {
        if let &ExprAssign(ref target, ref  src) = &e.node {
            if is_string(cx, target) && is_add(src, target) {
                span_lint(cx, STRING_ADD_ASSIGN, e.span,
                    "you assign the result of adding something to this string. \
                    Consider using `String::push_str()` instead")
            }
        }
    }
}

fn is_string(cx: &Context, e: &Expr) -> bool {
    let ty = walk_ptrs_ty(cx.tcx.expr_ty(e));
    if let TyStruct(did, _) = ty.sty {
        match_def_path(cx, did.did, &["collections", "string", "String"])
    } else { false }
}

fn is_add(src: &Expr, target: &Expr) -> bool {
    match &src.node {
        &ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) =>
            is_exp_equal(target, left),
        &ExprBlock(ref block) => block.stmts.is_empty() &&
            block.expr.as_ref().map_or(false, |expr| is_add(&*expr, target)),
        &ExprParen(ref expr) => is_add(&*expr, target),
        _ => false
    }
}
<|endoftext|>


<commit_before>pub use kay::External;
pub use descartes::{N, P3, P2, V3, V4, M4, Iso3, Persp3, ToHomogeneous, Norm, Into2d, Into3d,
                    WithUniqueOrthogonal, Inverse, Rotate};

use glium::{self, index};
use glium::backend::glutin_backend::GlutinFacade;

use compact::CVec;
use std::collections::HashMap;

#[derive(Copy, Clone, Debug)]
pub struct Vertex {
    pub position: [f32; 3],
}

implement_vertex!(Vertex, position);

#[derive(Copy, Clone)]
pub struct Instance {
    pub instance_position: [f32; 3],
    pub instance_direction: [f32; 2],
    pub instance_color: [f32; 3],
}

implement_vertex!(
    Instance,
    instance_position,
    instance_direction,
    instance_color
);

impl Instance {
    pub fn with_color(color: [f32; 3]) -> Instance {
        Instance {
            instance_position: [0.0, 0.0, 0.0],
            instance_direction: [1.0, 0.0],
            instance_color: color,
        }
    }
}

#[derive(Compact, Debug)]
pub struct Geometry {
    pub vertices: CVec<Vertex>,
    pub indices: CVec<u16>,
}

impl Geometry {
    pub fn new(vertices: Vec<Vertex>, indices: Vec<u16>) -> Geometry {
        Geometry {
            vertices: vertices.into(),
            indices: indices.into(),
        }
    }
}

impl Clone for Geometry {
    fn clone(&self) -> Geometry {
        Geometry {
            vertices: self.vertices.to_vec().into(),
            indices: self.indices.to_vec().into(),
        }
    }
}

impl ::std::ops::Add for Geometry {
    type Output = Geometry;

    fn add(mut self, rhs: Geometry) -> Geometry {
        let self_n_vertices = self.vertices.len();
        self.vertices.extend_from_copy_slice(&rhs.vertices);
        self.indices.extend(rhs.indices.iter().map(|i| {
            *i + self_n_vertices as u16
        }));
        self
    }
}

impl ::std::ops::AddAssign for Geometry {
    fn add_assign(&mut self, rhs: Geometry) {
        let self_n_vertices = self.vertices.len();
        for vertex in rhs.vertices.iter().cloned() {
            self.vertices.push(vertex);
        }
        for index in rhs.indices.iter() {
            self.indices.push(index + self_n_vertices as u16)
        }
    }
}

impl ::std::iter::Sum for Geometry {
    fn sum<I: Iterator<Item = Geometry>>(iter: I) -> Geometry {
        let mut summed_geometry = Geometry {
            vertices: CVec::new(),
            indices: CVec::new(),
        };
        for geometry in iter {
            summed_geometry += geometry;
        }
        summed_geometry
    }
}

impl<'a> ::std::ops::AddAssign<&'a Geometry> for Geometry {
    fn add_assign(&mut self, rhs: &'a Geometry) {
        let self_n_vertices = self.vertices.len();
        for vertex in rhs.vertices.iter().cloned() {
            self.vertices.push(vertex);
        }
        for index in rhs.indices.iter() {
            self.indices.push(index + self_n_vertices as u16)
        }
    }
}

impl<'a> ::std::iter::Sum<&'a Geometry> for Geometry {
    fn sum<I: Iterator<Item = &'a Geometry>>(iter: I) -> Geometry {
        let mut summed_geometry = Geometry {
            vertices: CVec::new(),
            indices: CVec::new(),
        };
        for geometry in iter {
            summed_geometry += geometry;
        }
        summed_geometry
    }
}

use compact::CDict;
use kay::{ActorSystem, Fate, World};
use kay::swarm::Swarm;
use itertools::Itertools;

pub trait GrouperIndividual {
    fn render_to_grouper(&mut self, grouper: GrouperID, individual_id: u16, world: &mut World);
}

pub struct GrouperInner {
    instance_color: [f32; 3],
    individual_id: u16,
    is_decal: bool,
    living_individuals: HashMap<GrouperIndividualID, Geometry>,
    frozen_individuals: HashMap<GrouperIndividualID, Geometry>,
    n_frozen_groups: usize,
    n_total_groups: usize,
    cached_frozen_individuals_clean_in: HashMap<RendererID, ()>,
}

#[derive(Compact, Clone)]
pub struct Grouper {
    id: GrouperID,
    inner: External<GrouperInner>,
}

impl ::std::ops::Deref for Grouper {
    type Target = GrouperInner;

    fn deref(&self) -> &GrouperInner {
        &self.inner
    }
}

impl ::std::ops::DerefMut for Grouper {
    fn deref_mut(&mut self) -> &mut GrouperInner {
        &mut self.inner
    }
}

impl Grouper {
    pub fn spawn(
        id: GrouperID,
        instance_color: &[f32; 3],
        individual_id: u16,
        is_decal: bool,
        _: &mut World,
    ) -> Grouper {
        Grouper {
            id,
            inner: External::new(GrouperInner {
                instance_color: *instance_color,
                individual_id: individual_id,
                is_decal: is_decal,
                living_individuals: HashMap::new(),
                frozen_individuals: HashMap::new(),
                n_frozen_groups: 0,
                cached_frozen_individuals_clean_in: HashMap::new(),
                n_total_groups: 0,
            }),
        }
    }

    pub fn initial_add(&mut self, id: GrouperIndividualID, world: &mut World) {
        id.render_to_grouper(self.id, self.individual_id, world);
    }

    pub fn update(&mut self, id: GrouperIndividualID, geometry: &Geometry, _: &mut World) {
        if self.frozen_individuals.get(&id).is_none() {
            self.living_individuals.insert(id, geometry.clone());
        }
    }

    pub fn freeze(&mut self, id: GrouperIndividualID, _: &mut World) {
        if let Some(geometry) = self.living_individuals.remove(&id) {
            self.frozen_individuals.insert(id, geometry);
            self.cached_frozen_individuals_clean_in = HashMap::new();
        }
    }

    pub fn unfreeze(&mut self, id: GrouperIndividualID, _: &mut World) {
        if let Some(geometry) = self.frozen_individuals.remove(&id) {
            self.living_individuals.insert(id, geometry);
            self.cached_frozen_individuals_clean_in = HashMap::new();
        }
    }

    pub fn remove(&mut self, id: GrouperIndividualID, _: &mut World) {
        self.living_individuals.remove(&id);
        if self.frozen_individuals.remove(&id).is_some() {
            self.cached_frozen_individuals_clean_in = HashMap::new();
        };
    }
}

use {Renderable, RendererID, RenderableID, MSG_Renderable_setup_in_scene,
     MSG_Renderable_render_to_scene};

impl Renderable for Grouper {
    fn setup_in_scene(&mut self, _renderer_id: RendererID, _scene_id: usize, _: &mut World) {}

    fn render_to_scene(&mut self, renderer_id: RendererID, scene_id: usize, world: &mut World) {
        // TODO: this introduces 1 frame delay
        for id in self.living_individuals.keys() {
            id.render_to_grouper(self.id, self.individual_id, world);
        }

        let clean_in_renderer = self.cached_frozen_individuals_clean_in
            .get(&renderer_id)
            .is_none();

        if clean_in_renderer {
            let new_n_frozen_groups = {
                let cached_frozen_individuals_grouped = self.frozen_individuals
                    .values()
                    .cloned()
                    .coalesce(|a, b| if a.vertices.len() + b.vertices.len() >
                        u16::max_value() as usize
                    {
                        Err((a, b))
                    } else {
                        Ok(a + b)
                    });

                let mut new_n_frozen_groups = 0;

                for frozen_group in cached_frozen_individuals_grouped {
                    renderer_id.update_individual(
                        scene_id,
                        self.individual_id + self.n_frozen_groups as u16,
                        frozen_group,
                        Instance {
                            instance_position: [0.0, 0.0, -0.1],
                            instance_direction: [1.0, 0.0],
                            instance_color: self.instance_color,
                        },
                        self.is_decal,
                        world,
                    );

                    new_n_frozen_groups += 1;
                }

                new_n_frozen_groups
            };

            self.n_frozen_groups = new_n_frozen_groups;

            self.cached_frozen_individuals_clean_in.insert(
                renderer_id,
                (),
            );
        }

        let mut new_n_total_groups = self.n_frozen_groups;

        {
            let living_individual_groups = self.living_individuals.values().cloned().coalesce(
                |a, b| if a.vertices.len() + b.vertices.len() >
                    u16::max_value() as
                        usize
                {
                    Err((a, b))
                } else {
                    Ok(a + b)
                },
            );

            for living_individual_group in living_individual_groups {
                renderer_id.update_individual(
                    scene_id,
                    self.individual_id + new_n_total_groups as u16,
                    living_individual_group,
                    Instance {
                        instance_position: [0.0, 0.0, -0.1],
                        instance_direction: [1.0, 0.0],
                        instance_color: self.instance_color,
                    },
                    self.is_decal,
                    world,
                );

                new_n_total_groups += 1;
            }

            if new_n_total_groups > self.n_total_groups {
                for individual_to_empty_id in new_n_total_groups..self.n_total_groups {
                    renderer_id.update_individual(
                        scene_id,
                        self.individual_id + individual_to_empty_id as u16,
                        Geometry::new(vec![], vec![]),
                        Instance::with_color([0.0, 0.0, 0.0]),
                        self.is_decal,
                        world,
                    );
                }
            }
        }

        self.n_total_groups = new_n_total_groups;
    }
}

pub struct Batch {
    pub vertices: glium::VertexBuffer<Vertex>,
    pub indices: glium::IndexBuffer<u16>,
    pub instances: Vec<Instance>,
    pub clear_every_frame: bool,
    pub is_decal: bool,
}

impl Batch {
    pub fn new(prototype: Geometry, window: &GlutinFacade) -> Batch {
        Batch {
            vertices: glium::VertexBuffer::new(window, &prototype.vertices).unwrap(),
            indices: glium::IndexBuffer::new(
                window,
                index::PrimitiveType::TrianglesList,
                &prototype.indices,
            ).unwrap(),
            instances: Vec::new(),
            clear_every_frame: true,
            is_decal: false,
        }
    }

    pub fn new_individual(
        geometry: Geometry,
        instance: Instance,
        is_decal: bool,
        window: &GlutinFacade,
    ) -> Batch {
        Batch {
            vertices: glium::VertexBuffer::new(window, &geometry.vertices).unwrap(),
            indices: glium::IndexBuffer::new(
                window,
                index::PrimitiveType::TrianglesList,
                &geometry.indices,
            ).unwrap(),
            instances: vec![instance],
            clear_every_frame: false,
            is_decal: is_decal,
        }
    }
}

pub fn setup(system: &mut ActorSystem) {
    system.add(Swarm::<Grouper>::new(), |_| {});

    auto_setup(system);
}

mod kay_auto;
pub use self::kay_auto::*;<commit_msg>Fix the implementation of Grouper<commit_after>pub use kay::External;
pub use descartes::{N, P3, P2, V3, V4, M4, Iso3, Persp3, ToHomogeneous, Norm, Into2d, Into3d,
                    WithUniqueOrthogonal, Inverse, Rotate};

use glium::{self, index};
use glium::backend::glutin_backend::GlutinFacade;

use compact::CVec;
use std::collections::HashMap;

#[derive(Copy, Clone, Debug)]
pub struct Vertex {
    pub position: [f32; 3],
}

implement_vertex!(Vertex, position);

#[derive(Copy, Clone)]
pub struct Instance {
    pub instance_position: [f32; 3],
    pub instance_direction: [f32; 2],
    pub instance_color: [f32; 3],
}

implement_vertex!(
    Instance,
    instance_position,
    instance_direction,
    instance_color
);

impl Instance {
    pub fn with_color(color: [f32; 3]) -> Instance {
        Instance {
            instance_position: [0.0, 0.0, 0.0],
            instance_direction: [1.0, 0.0],
            instance_color: color,
        }
    }
}

#[derive(Compact, Debug)]
pub struct Geometry {
    pub vertices: CVec<Vertex>,
    pub indices: CVec<u16>,
}

impl Geometry {
    pub fn new(vertices: Vec<Vertex>, indices: Vec<u16>) -> Geometry {
        Geometry {
            vertices: vertices.into(),
            indices: indices.into(),
        }
    }
}

impl Clone for Geometry {
    fn clone(&self) -> Geometry {
        Geometry {
            vertices: self.vertices.to_vec().into(),
            indices: self.indices.to_vec().into(),
        }
    }
}

impl ::std::ops::Add for Geometry {
    type Output = Geometry;

    fn add(mut self, rhs: Geometry) -> Geometry {
        let self_n_vertices = self.vertices.len();
        self.vertices.extend_from_copy_slice(&rhs.vertices);
        self.indices.extend(rhs.indices.iter().map(|i| {
            *i + self_n_vertices as u16
        }));
        self
    }
}

impl ::std::ops::AddAssign for Geometry {
    fn add_assign(&mut self, rhs: Geometry) {
        let self_n_vertices = self.vertices.len();
        for vertex in rhs.vertices.iter().cloned() {
            self.vertices.push(vertex);
        }
        for index in rhs.indices.iter() {
            self.indices.push(index + self_n_vertices as u16)
        }
    }
}

impl ::std::iter::Sum for Geometry {
    fn sum<I: Iterator<Item = Geometry>>(iter: I) -> Geometry {
        let mut summed_geometry = Geometry {
            vertices: CVec::new(),
            indices: CVec::new(),
        };
        for geometry in iter {
            summed_geometry += geometry;
        }
        summed_geometry
    }
}

impl<'a> ::std::ops::AddAssign<&'a Geometry> for Geometry {
    fn add_assign(&mut self, rhs: &'a Geometry) {
        let self_n_vertices = self.vertices.len();
        for vertex in rhs.vertices.iter().cloned() {
            self.vertices.push(vertex);
        }
        for index in rhs.indices.iter() {
            self.indices.push(index + self_n_vertices as u16)
        }
    }
}

impl<'a> ::std::iter::Sum<&'a Geometry> for Geometry {
    fn sum<I: Iterator<Item = &'a Geometry>>(iter: I) -> Geometry {
        let mut summed_geometry = Geometry {
            vertices: CVec::new(),
            indices: CVec::new(),
        };
        for geometry in iter {
            summed_geometry += geometry;
        }
        summed_geometry
    }
}

use compact::CDict;
use kay::{ActorSystem, Fate, World};
use kay::swarm::Swarm;
use itertools::Itertools;

pub trait GrouperIndividual {
    fn render_to_grouper(&mut self, grouper: GrouperID, base_individual_id: u16, world: &mut World);
}

#[derive(Clone)]
struct GrouperRendererState {
    n_living_groups: usize,
    n_frozen_groups: usize,
    frozen_up_to_date: bool,
}

pub struct GrouperInner {
    instance_color: [f32; 3],
    base_individual_id: u16,
    is_decal: bool,
    living_individuals: HashMap<GrouperIndividualID, Geometry>,
    frozen_individuals: HashMap<GrouperIndividualID, Geometry>,
    living_groups: Vec<Geometry>,
    frozen_groups: Vec<Geometry>,
    frozen_up_to_date: bool,
    renderer_state: HashMap<RendererID, GrouperRendererState>,
}

#[derive(Compact, Clone)]
pub struct Grouper {
    id: GrouperID,
    inner: External<GrouperInner>,
}

impl ::std::ops::Deref for Grouper {
    type Target = GrouperInner;

    fn deref(&self) -> &GrouperInner {
        &self.inner
    }
}

impl ::std::ops::DerefMut for Grouper {
    fn deref_mut(&mut self) -> &mut GrouperInner {
        &mut self.inner
    }
}

impl Grouper {
    pub fn spawn(
        id: GrouperID,
        instance_color: &[f32; 3],
        base_individual_id: u16,
        is_decal: bool,
        _: &mut World,
    ) -> Grouper {
        Grouper {
            id,
            inner: External::new(GrouperInner {
                instance_color: *instance_color,
                base_individual_id: base_individual_id,
                is_decal: is_decal,
                living_individuals: HashMap::new(),
                frozen_individuals: HashMap::new(),
                living_groups: Vec::new(),
                frozen_groups: Vec::new(),
                frozen_up_to_date: true,
                renderer_state: HashMap::new(),
            }),
        }
    }

    pub fn initial_add(&mut self, id: GrouperIndividualID, world: &mut World) {
        id.render_to_grouper(self.id, self.base_individual_id, world);
    }

    pub fn update(&mut self, id: GrouperIndividualID, geometry: &Geometry, _: &mut World) {
        if self.frozen_individuals.get(&id).is_none() {
            self.living_individuals.insert(id, geometry.clone());
        }
    }

    pub fn freeze(&mut self, id: GrouperIndividualID, _: &mut World) {
        if let Some(geometry) = self.living_individuals.remove(&id) {
            self.frozen_individuals.insert(id, geometry);
            self.frozen_up_to_date = false;
            for (_renderer, state) in self.renderer_state.iter_mut() {
                state.frozen_up_to_date = false;
            }
        }
    }

    pub fn unfreeze(&mut self, id: GrouperIndividualID, _: &mut World) {
        if let Some(geometry) = self.frozen_individuals.remove(&id) {
            self.living_individuals.insert(id, geometry);
            self.frozen_up_to_date = false;
            for (_renderer, state) in self.renderer_state.iter_mut() {
                state.frozen_up_to_date = false;
            }
        }
    }

    pub fn remove(&mut self, id: GrouperIndividualID, _: &mut World) {
        self.living_individuals.remove(&id);
        if self.frozen_individuals.remove(&id).is_some() {
            self.frozen_up_to_date = false;
            for (_renderer, state) in self.renderer_state.iter_mut() {
                state.frozen_up_to_date = false;
            }
        };
    }
}

use {Renderable, RendererID, RenderableID, MSG_Renderable_setup_in_scene,
     MSG_Renderable_render_to_scene};

impl Renderable for Grouper {
    fn setup_in_scene(&mut self, _renderer_id: RendererID, _scene_id: usize, _: &mut World) {}

    fn render_to_scene(&mut self, renderer_id: RendererID, scene_id: usize, world: &mut World) {

        // kinda ugly way to enforce only one update per "global" frame
        if renderer_id._raw_id.machine == self.id._raw_id.machine {
            // TODO: this introduces 1 frame delay
            for id in self.living_individuals.keys() {
                id.render_to_grouper(self.id, self.base_individual_id, world);
            }

            self.living_groups = self.living_individuals
                .values()
                .cloned()
                .coalesce(|a, b| if a.vertices.len() + b.vertices.len() >
                    u16::max_value() as usize
                {
                    Err((a, b))
                } else {
                    Ok(a + b)
                })
                .collect();

            if !self.frozen_up_to_date {
                self.frozen_groups = self.frozen_individuals
                    .values()
                    .cloned()
                    .coalesce(|a, b| if a.vertices.len() + b.vertices.len() >
                        u16::max_value() as usize
                    {
                        Err((a, b))
                    } else {
                        Ok(a + b)
                    })
                    .collect();

                self.frozen_up_to_date = true;
            }
        }

        let mut new_renderer_state = self.renderer_state.get(&renderer_id).cloned().unwrap_or(
            GrouperRendererState {
                n_living_groups: 0,
                n_frozen_groups: 0,
                frozen_up_to_date: false,
            },
        );

        for (i, living_group) in self.living_groups.iter().enumerate() {
            renderer_id.update_individual(
                scene_id,
                self.base_individual_id + i as u16,
                living_group.clone(),
                Instance {
                    instance_position: [0.0, 0.0, -0.1],
                    instance_direction: [1.0, 0.0],
                    instance_color: self.instance_color,
                },
                self.is_decal,
                world,
            );
        }

        for i in self.living_groups.len()..new_renderer_state.n_living_groups {
            renderer_id.update_individual(
                scene_id,
                self.base_individual_id + i as u16,
                Geometry::new(vec![], vec![]),
                Instance::with_color([0.0, 0.0, 0.0]),
                self.is_decal,
                world,
            );
        }

        new_renderer_state.n_living_groups = self.living_groups.len();

        const FROZEN_OFFSET: u16 = 50;

        if !new_renderer_state.frozen_up_to_date {
            for (i, frozen_group) in self.frozen_groups.iter().enumerate() {
                renderer_id.update_individual(
                    scene_id,
                    self.base_individual_id + FROZEN_OFFSET + i as u16,
                    frozen_group.clone(),
                    Instance {
                        instance_position: [0.0, 0.0, -0.1],
                        instance_direction: [1.0, 0.0],
                        instance_color: self.instance_color,
                    },
                    self.is_decal,
                    world,
                );
            }

            for i in self.frozen_groups.len()..new_renderer_state.n_frozen_groups {
                renderer_id.update_individual(
                    scene_id,
                    self.base_individual_id + FROZEN_OFFSET + i as u16,
                    Geometry::new(vec![], vec![]),
                    Instance::with_color([0.0, 0.0, 0.0]),
                    self.is_decal,
                    world,
                );
            }

            new_renderer_state.n_frozen_groups = self.frozen_groups.len();
            new_renderer_state.frozen_up_to_date = true;
        }

        self.renderer_state.insert(renderer_id, new_renderer_state);
    }
}

pub struct Batch {
    pub vertices: glium::VertexBuffer<Vertex>,
    pub indices: glium::IndexBuffer<u16>,
    pub instances: Vec<Instance>,
    pub clear_every_frame: bool,
    pub is_decal: bool,
}

impl Batch {
    pub fn new(prototype: Geometry, window: &GlutinFacade) -> Batch {
        Batch {
            vertices: glium::VertexBuffer::new(window, &prototype.vertices).unwrap(),
            indices: glium::IndexBuffer::new(
                window,
                index::PrimitiveType::TrianglesList,
                &prototype.indices,
            ).unwrap(),
            instances: Vec::new(),
            clear_every_frame: true,
            is_decal: false,
        }
    }

    pub fn new_individual(
        geometry: Geometry,
        instance: Instance,
        is_decal: bool,
        window: &GlutinFacade,
    ) -> Batch {
        Batch {
            vertices: glium::VertexBuffer::new(window, &geometry.vertices).unwrap(),
            indices: glium::IndexBuffer::new(
                window,
                index::PrimitiveType::TrianglesList,
                &geometry.indices,
            ).unwrap(),
            instances: vec![instance],
            clear_every_frame: false,
            is_decal: is_decal,
        }
    }
}

pub fn setup(system: &mut ActorSystem) {
    system.add(Swarm::<Grouper>::new(), |_| {});

    auto_setup(system);
}

mod kay_auto;
pub use self::kay_auto::*;<|endoftext|>