1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
Copyright 2018 Johannes Boczek

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

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

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

use std::any::Any;
use std::rc::Rc;
use std::sync::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};

///A world struct containing all the entitites and systems
pub struct World<Context> {
	entities: Vec<Entity>,
	systems: Vec<Rc<Mutex<System<Context>>>>
}

///Represents an entity which constists of multiple components
pub struct Entity {
	components: Vec<Option<Box<Any>>>,
	bitmask: u64
}

///A component trait
///
///Each component should have a distinct ID
pub trait Component: 'static {
	const ID: u8;
	const BITMASK: u64 = 1 << (Self::ID & 0b00111111) as u64;
}

///The system trait
pub trait System<Context> {
	///Processes an entity
	fn handle(&mut self, ctx: &mut Context, entity: &mut Entity) -> bool;
	
	///Specifies the bitmask which determines the entities this system should handle
	fn bitmask(&self) -> u64;
}

impl<Context> World<Context> {
	///Creates a new world
	pub fn new() -> Self {
		World {
			entities: Vec::new(),
			systems: Vec::new()
		}
	}
	
	///Adds a new entity to the world
	pub fn add(&mut self, entity: Entity) {
		self.entities.push(entity);
	}
	
	///Registers a new system
	pub fn register<T>(&mut self, system: T) -> Rc<Mutex<T>> where T: System<Context> + 'static {
		let rc_lock = Rc::new(Mutex::new(system));
		
		self.systems.push(rc_lock.clone());
		
		rc_lock
	}
	
	///Iterates over all systems and passes the entities that match the criteria
	pub fn dispatch(&mut self, ctx: &mut Context) {
		for system in self.systems.iter_mut() {
			let mut system = if let Ok(guard) = system.lock() {
				guard
			} else {
				continue
			};
			let system_bitmask = system.bitmask();
			
			for i in (0 .. self.entities.len()).rev() {
				let remove = {
					let entity = &mut self.entities[i];
					
					if system_bitmask & entity.bitmask == system_bitmask {
						system.handle(ctx, entity)
					} else {
						false
					}
				};
				
				if remove {
					self.entities.swap_remove(i);
				}
			}
		}
	}
}

impl Entity {
	///Creates a new entity
	pub fn new() -> Self {
		let mut entity = Entity {
			components: Vec::with_capacity(64),
			bitmask: 0
		};
		
		for _ in 0 .. entity.components.capacity() {
			entity.components.push(None);
		}
		
		entity
	}
	
	///Adds a component to an entity
	pub fn add<T>(&mut self, component: T) where T: Component {
		let boxed_lock = Box::new(RwLock::new(component)) as Box<Any>;
		
		self.components[T::ID as usize] = Some(boxed_lock);
		self.bitmask |= T::BITMASK;
	}
	
	///Removes a component from an entity
	pub fn remove<T>(&mut self) -> Option<T> where T: Component {
		self.components[T::ID as usize].take()
			.and_then(|boxed_any| boxed_any.downcast().ok())
			.and_then(|boxed_lock| *boxed_lock)
			.and_then(|lock: RwLock<T>| lock.into_inner().ok())
	}
	
	///Returns read access to a component
	pub fn get<T>(&self) -> Option<RwLockReadGuard<T>> where T: Component {
		self.components[T::ID as usize].as_ref()
			.and_then(|component| component.downcast_ref())
			.and_then(|lock: &RwLock<T>| lock.read().ok())
	}
	
	///Returns write access to a component
	pub fn get_mut<T>(&self) -> Option<RwLockWriteGuard<T>> where T: Component {
		self.components[T::ID as usize].as_ref()
			.and_then(|component| component.downcast_ref())
			.and_then(|lock: &RwLock<T>| lock.write().ok())
	}
}