1use std::{
2 any::{Any, TypeId},
3 cell::UnsafeCell,
4 collections::HashMap,
5};
6
7mod commands;
8mod query;
9mod resources;
10
11pub use self::{
12 commands::Commands,
13 query::Query,
14 resources::{Res, Resources},
15};
16
17use crate::{
18 bundle::{Bundle, BundleMeta},
19 storage::{Chunk, Entity, CHUNK_SIZE},
20 tools::{Command, ResManager},
21};
22
23type AnRes = UnsafeCell<Option<Box<dyn Any>>>;
27
28type Droper = Option<Box<dyn FnOnce(&mut AnRes)>>;
29
30#[cfg(feature = "system")]
31use crate::system::{InnerSystem, System};
32
33pub struct World {
34 pub(crate) chunks: Vec<Chunk>,
35 pub(crate) metas: HashMap<TypeId, BundleMeta>,
36 #[cfg(feature = "system")]
37 pub(crate) startup_systems: Vec<System>,
38 #[cfg(feature = "system")]
39 pub(crate) systems: Vec<System>,
40 pub(crate) resources: HashMap<TypeId, AnRes>,
41 pub(crate) resources_dropers: HashMap<TypeId, Droper>,
46}
47
48impl World {
49 pub fn new() -> Self {
50 Self {
51 chunks: vec![],
52 metas: Default::default(),
53 #[cfg(feature = "system")]
54 startup_systems: vec![],
55 #[cfg(feature = "system")]
56 systems: vec![],
57 resources: Default::default(),
58 resources_dropers: Default::default(),
59 }
60 }
61
62 pub(crate) fn new_chunk<B: Bundle>(&mut self) -> &mut Chunk {
66 self.metas
67 .get_mut(&B::type_id_())
68 .unwrap()
69 .chunks
70 .push(self.chunks.len());
71 self.chunks.push(Chunk::new::<B>(self.chunks.len()));
72 self.chunks.last_mut().unwrap()
73 }
74}
75
76#[cfg(feature = "system")]
77impl World {
78 #[cfg(not(feature = "async"))]
79 pub fn exec<M, S: InnerSystem<M>>(&self, mut s: S) {
80 s.run_once(s.build_args(self));
81 }
82
83 #[cfg(feature = "async")]
84 pub async fn exec<M, S: InnerSystem<M>>(&self, mut s: S) {
85 s.run_once(s.build_args(self)).await;
86 }
87
88 pub fn add_system<M, S: InnerSystem<M>>(&mut self, system: S) -> &mut Self {
92 self.systems.push(System::new(system));
93 self
94 }
95
96 pub fn add_startup_system<M, S: InnerSystem<M>>(&mut self, system: S) -> &mut Self {
100 self.startup_systems.push(System::new(system));
101 self
102 }
103
104 #[cfg(not(feature = "async"))]
110 pub fn run(&mut self) {
111 self.run_until(|| false)
112 }
113 #[cfg(feature = "async")]
114 pub async fn run(&mut self) {
115 self.run_until(|| false).await;
116 }
117
118 #[cfg(not(feature = "async"))]
119 pub fn run_until<F>(&mut self, mut until: F)
120 where
121 F: FnMut() -> bool,
122 {
123 loop {
124 if until() {
125 return;
126 }
127
128 self.startup();
129 self.run_once();
130 }
131 }
132
133 #[cfg(feature = "async")]
134 pub async fn run_until<F>(&mut self, mut until: F)
135 where
136 F: FnMut() -> bool,
137 {
138 loop {
139 if until() {
140 return;
141 }
142
143 self.startup().await;
144 self.run_once().await;
145 }
146 }
147
148 #[cfg(not(feature = "async"))]
149 pub fn startup(&mut self) -> &mut Self {
150 while let Some(mut stsys) = self.startup_systems.pop() {
151 stsys.run_once(self);
152 }
153 self
154 }
155
156 #[cfg(feature = "async")]
157 pub async fn startup(&mut self) -> &mut Self {
158 while let Some(mut stsys) = self.startup_systems.pop() {
159 stsys.run_once(self).await;
160 }
161 self
162 }
163
164 #[cfg(not(feature = "async"))]
166 pub fn run_once(&mut self) {
167 let this = unsafe {
168 #[allow(unknown_lints)]
170 #[allow(clippy::cast_ref_to_mut)]
172 &mut *(self as *const _ as *mut World)
173 };
174 for sys in &mut self.systems {
175 sys.run_once(this);
176 }
177 }
178 #[cfg(feature = "async")]
179 pub async fn run_once(&mut self) {
180 let this = unsafe {
181 #[allow(unknown_lints)]
183 #[allow(clippy::cast_ref_to_mut)]
185 &mut *(self as *const _ as *mut World)
186 };
187 for sys in &mut self.systems {
188 sys.run_once(this).await;
189 }
190 }
191}
192
193impl Default for World {
194 fn default() -> Self {
195 Self::new()
196 }
197}
198
199fn rev_result<T, E>(result: Result<T, E>) -> Result<E, T> {
203 match result {
204 Ok(o) => Err(o),
205 Err(e) => Ok(e),
206 }
207}
208
209impl Command for World {
210 fn register<B: crate::bundle::Bundle>(&mut self) {
211 let bundle_id = B::type_id_();
212 self.metas
213 .entry(bundle_id)
214 .or_insert_with(|| BundleMeta::new::<B>());
215 }
216
217 fn spawn<B: crate::bundle::Bundle>(&mut self, b: B) -> crate::storage::Entity {
218 self.register::<B>();
219 let bundle_id = B::type_id_();
220 let mut bundle = Some(b);
221
222 let meta = self.metas.get_mut(&bundle_id).unwrap();
223
224 meta.chunks
225 .iter()
226 .try_fold((), |_, &cid| {
227 bundle = Some(rev_result(self.chunks[cid].insert(bundle.take().unwrap()))?);
229 Ok(())
230 })
231 .err()
232 .unwrap_or_else(|| self.new_chunk::<B>().insert(bundle?).ok())
233 .unwrap()
234 }
235
236 fn spawn_many<B: crate::bundle::Bundle, I: IntoIterator<Item = B>>(
237 &mut self,
238 i: I,
239 ) -> Vec<Entity> {
240 self.register::<B>();
242 let mut i = i.into_iter();
246 let mut chuns_iter = self
247 .metas
248 .get_mut(&B::type_id_())
249 .unwrap()
250 .chunks
251 .clone()
252 .into_iter();
253
254 let mut entities = vec![];
255
256 let mut temp_bundle: Option<B> = None;
257
258 loop {
259 let Some(_temp_bundle) = temp_bundle.take().or_else(|| i.next()) else {return entities;};
261 temp_bundle = Some(_temp_bundle);
262
263 let temp_chunk = 'get_chunk: {
264 if let Some(cid) = chuns_iter.next() {
265 if let Some(chunk) = self.chunks.get_mut(cid) {
266 break 'get_chunk chunk;
267 }
268 }
269 self.new_chunk::<B>()
270 };
271
272 let eneity_iter = (0..temp_chunk.free()).filter_map(|_| {
273 let item = temp_bundle.take().or_else(|| i.next())?;
274 temp_chunk
275 .insert(item)
276 .map_err(|b| temp_bundle = b.into())
277 .ok()
278 });
279
280 entities.extend(eneity_iter);
281 }
282
283 }
312
313 fn alive(&self, entity: crate::storage::Entity) -> Option<bool> {
314 self.chunks.get(entity.index / CHUNK_SIZE)?.alive(entity)
315 }
316
317 fn remove(&mut self, entity: crate::storage::Entity) -> bool {
318 self.chunks
319 .get_mut(entity.index / CHUNK_SIZE)
320 .map(|chunk| chunk.remove(entity))
321 .unwrap_or(false)
322 }
323
324 fn fetch<F: crate::tools::WorldFetch>(&mut self, entity: Entity) -> Option<F::Item<'_>> {
325 if !self.alive(entity).unwrap_or(false) {
332 return None;
333 }
334 unsafe {
335 let chunk = self.chunks.get(entity.chunk_index())?;
336 let components = chunk.get(entity.index_in_chunk());
337 let mapping_table = self.metas.get_mut(&chunk.bundle_id())?.fetch::<F>()?;
338 let item = F::build(components, mapping_table);
339 Some(item)
340 }
341 }
342}
343
344impl Drop for World {
345 fn drop(&mut self) {
346 for (t_id, droper) in &mut self.resources_dropers {
348 if let (Some(droper), Some(res)) = (droper.take(), self.resources.get_mut(t_id)) {
349 (droper)(res);
350 }
351 }
352
353 for (.., meta) in &self.metas {
355 meta.chunks
356 .iter()
357 .copied()
358 .filter_map(|cid| {
359 self.chunks.get_mut(cid)?.clear(&meta.droper);
360 Some(())
361 })
362 .count();
363 }
364 }
365}
366
367impl ResManager for World {
368 fn get_res<T: 'static>(&mut self) -> Res<'_, T> {
369 if !self.resources.contains_key(&TypeId::of::<T>()) {
370 self.new_res::<T>();
371 }
372 self.try_get_res::<T>().unwrap()
373 }
374
375 fn try_get_res<T: 'static>(&mut self) -> Option<Res<'_, T>> {
376 let t_id = TypeId::of::<T>();
377 let res = self.resources.get_mut(&t_id)?.get_mut();
378 Some(Res::new(res))
379 }
380
381 fn new_res<T: 'static>(&mut self) {
382 Resources {
383 resources: &mut self.resources,
384 resources_dropers: &mut self.resources_dropers,
385 }
386 .new_res::<T>();
387 }
388}
389
390#[cfg(test)]
391mod tests {
392 use crate::storage::ALIVE_TAG;
393
394 use super::*;
395
396 #[test]
397 fn command() {
398 let mut world = World::new();
399
400 let entity = world.spawn(12345);
402 world.remove(entity);
403
404 assert_eq!(world.spawn(114514).generator, ALIVE_TAG);
406
407 let last = *world.spawn_many(1..CHUNK_SIZE as i32).last().unwrap();
410
411 assert_eq!(entity.index, last.index);
413 assert_eq!(entity.generator, last.generator - 1);
414
415 assert_eq!(world.chunks.len(), 1);
417
418 let entity = world.spawn(12345);
420 assert_eq!(world.chunks.len(), 2);
421 assert_eq!(entity.index, CHUNK_SIZE);
422 }
423}