1#![allow(dead_code)]
26
27use std::{any::{Any, TypeId}, collections::HashMap};
28
29pub trait Component: 'static + Send + Sync + Clone {}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
46pub struct Entity {
47 pub index: u32,
49 pub generation: u32,
51}
52
53impl Entity {
54 #[inline] pub fn from_raw(index: u32, generation: u32) -> Self { Self { index, generation } }
56 #[inline] pub fn null() -> Self { Self { index: u32::MAX, generation: u32::MAX } }
58 #[inline] pub fn is_null(self) -> bool { self.index == u32::MAX }
60}
61
62impl std::fmt::Display for Entity {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 write!(f, "Entity({}v{})", self.index, self.generation)
65 }
66}
67
68#[derive(Debug, Clone)]
73struct EntityRecord { generation: u32, location: Option<EntityLocation> }
74
75#[derive(Debug, Clone, Copy)]
76struct EntityLocation { archetype_id: ArchetypeId, row: usize }
77
78#[derive(Debug, Default)]
79struct EntityAllocator { records: Vec<EntityRecord>, free: Vec<u32> }
80
81impl EntityAllocator {
82 fn alloc(&mut self) -> Entity {
83 if let Some(idx) = self.free.pop() {
84 let gen = self.records[idx as usize].generation;
85 Entity { index: idx, generation: gen }
86 } else {
87 let idx = self.records.len() as u32;
88 self.records.push(EntityRecord { generation: 0, location: None });
89 Entity { index: idx, generation: 0 }
90 }
91 }
92 fn free(&mut self, e: Entity) {
93 let r = &mut self.records[e.index as usize];
94 r.generation = r.generation.wrapping_add(1);
95 r.location = None;
96 self.free.push(e.index);
97 }
98 fn is_alive(&self, e: Entity) -> bool {
99 self.records.get(e.index as usize)
100 .map(|r| r.generation == e.generation && r.location.is_some())
101 .unwrap_or(false)
102 }
103 fn location(&self, e: Entity) -> Option<EntityLocation> {
104 self.records.get(e.index as usize)
105 .filter(|r| r.generation == e.generation)
106 .and_then(|r| r.location)
107 }
108 fn set_location(&mut self, e: Entity, loc: EntityLocation) {
109 if let Some(r) = self.records.get_mut(e.index as usize) {
110 if r.generation == e.generation { r.location = Some(loc); }
111 }
112 }
113}
114
115struct AnyVec {
120 type_id: TypeId,
121 len: usize,
122 data: Vec<u8>,
123 element_size: usize,
124 element_align: usize,
125 drop_fn: unsafe fn(*mut u8),
126 clone_fn: unsafe fn(*const u8, *mut u8),
127}
128unsafe impl Send for AnyVec {}
129unsafe impl Sync for AnyVec {}
130
131impl AnyVec {
132 fn new<T: Component>() -> Self {
133 let align = std::mem::align_of::<T>();
134 let size = std::mem::size_of::<T>();
135 let padded = if align > 0 && size > 0 { (size + align - 1) & !(align - 1) } else { size };
137 Self {
138 type_id: TypeId::of::<T>(),
139 len: 0,
140 data: Vec::new(),
141 element_size: padded,
142 element_align: align,
143 drop_fn: |p| unsafe { std::ptr::drop_in_place(p as *mut T) },
144 clone_fn: |s, d| unsafe { std::ptr::write(d as *mut T, (*(s as *const T)).clone()) },
145 }
146 }
147
148 fn reserve_one(&mut self) {
149 let sz = self.element_size;
150 if sz == 0 { return; }
151 let need = (self.len + 1) * sz + self.element_align; if self.data.len() < need {
153 self.data.resize(need.max(self.data.len() * 2).max(sz * 4 + self.element_align), 0);
154 }
155 }
156
157 fn aligned_base(&self) -> *const u8 {
159 let ptr = self.data.as_ptr() as usize;
160 let align = self.element_align.max(1);
161 let aligned = (ptr + align - 1) & !(align - 1);
162 aligned as *const u8
163 }
164
165 fn aligned_base_mut(&mut self) -> *mut u8 {
166 let ptr = self.data.as_mut_ptr() as usize;
167 let align = self.element_align.max(1);
168 let aligned = (ptr + align - 1) & !(align - 1);
169 aligned as *mut u8
170 }
171
172 fn push<T: Component>(&mut self, v: T) {
173 self.reserve_one();
174 unsafe { std::ptr::write(self.aligned_base_mut().add(self.len * self.element_size) as *mut T, v); }
175 self.len += 1;
176 }
177
178 fn get<T: Component>(&self, row: usize) -> &T {
179 unsafe { &*(self.aligned_base().add(row * self.element_size) as *const T) }
180 }
181
182 fn get_mut<T: Component>(&mut self, row: usize) -> &mut T {
183 unsafe { &mut *(self.aligned_base_mut().add(row * self.element_size) as *mut T) }
184 }
185
186 fn get_ptr(&self, row: usize) -> *const u8 {
187 unsafe { self.aligned_base().add(row * self.element_size) }
188 }
189
190 fn swap_remove_raw(&mut self, row: usize) {
191 let last = self.len - 1;
192 let sz = self.element_size;
193 unsafe {
194 let base = self.aligned_base_mut();
195 let dst = base.add(row * sz);
196 (self.drop_fn)(dst);
197 if row != last {
198 let src = base.add(last * sz) as *const u8;
199 std::ptr::copy_nonoverlapping(src, dst, sz);
200 }
201 }
202 self.len -= 1;
203 }
204}
205
206impl Drop for AnyVec {
207 fn drop(&mut self) {
208 for i in 0..self.len {
209 unsafe { (self.drop_fn)(self.aligned_base_mut().add(i * self.element_size)); }
210 }
211 }
212}
213
214struct ComponentStorage {
219 column: AnyVec,
220 added_ticks: Vec<u32>,
221 changed_ticks: Vec<u32>,
222}
223
224impl ComponentStorage {
225 fn new<T: Component>() -> Self {
226 Self { column: AnyVec::new::<T>(), added_ticks: Vec::new(), changed_ticks: Vec::new() }
227 }
228
229 fn push<T: Component>(&mut self, v: T, tick: u32) {
230 self.column.push(v);
231 self.added_ticks.push(tick);
232 self.changed_ticks.push(tick);
233 }
234
235 fn swap_remove(&mut self, row: usize) {
236 self.column.swap_remove_raw(row);
237 let last = self.added_ticks.len() - 1;
238 self.added_ticks.swap(row, last); self.added_ticks.pop();
239 let last = self.changed_ticks.len() - 1;
240 self.changed_ticks.swap(row, last); self.changed_ticks.pop();
241 }
242
243 fn clone_row_into(&self, row: usize, dst: &mut ComponentStorage, tick: u32) {
245 let sz = self.column.element_size;
246 let need = (dst.column.len + 1) * sz;
247 if dst.column.data.len() < need {
248 dst.column.data.resize(need.max(dst.column.data.len() * 2).max(sz * 4), 0);
249 }
250 unsafe {
251 let s = self.column.aligned_base().add(row * sz);
252 let d = dst.column.aligned_base_mut().add(dst.column.len * sz);
253 (self.column.clone_fn)(s, d);
254 }
255 dst.column.len += 1;
256 dst.added_ticks.push(self.added_ticks[row]);
257 dst.changed_ticks.push(tick);
258 }
259}
260
261#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
267pub struct ArchetypeId(pub u32);
268
269pub struct Archetype {
271 pub id: ArchetypeId,
273 pub component_types: Vec<TypeId>,
275 columns: HashMap<TypeId, ComponentStorage>,
276 pub entities: Vec<Entity>,
278}
279
280impl Archetype {
281 fn new(id: ArchetypeId, types: Vec<TypeId>) -> Self {
282 Self { id, component_types: types, columns: HashMap::new(), entities: Vec::new() }
283 }
284
285 fn register_column<T: Component>(&mut self) {
286 self.columns.entry(TypeId::of::<T>()).or_insert_with(ComponentStorage::new::<T>);
287 }
288
289 pub fn contains(&self, tid: TypeId) -> bool { self.columns.contains_key(&tid) }
291
292 pub fn len(&self) -> usize { self.entities.len() }
294
295 pub fn is_empty(&self) -> bool { self.entities.is_empty() }
297
298 fn swap_remove(&mut self, row: usize) -> Option<Entity> {
300 let last = self.entities.len() - 1;
301 for col in self.columns.values_mut() { col.swap_remove(row); }
302 self.entities.swap(row, last);
303 self.entities.pop();
304 if row < self.entities.len() { Some(self.entities[row]) } else { None }
305 }
306}
307
308pub trait Bundle: 'static + Send + Sync {
314 fn type_ids() -> Vec<TypeId>;
316 fn register_columns(arch: &mut Archetype);
318 fn insert_into(self, arch: &mut Archetype, tick: u32);
320}
321
322impl<C: Component> Bundle for C {
323 fn type_ids() -> Vec<TypeId> { vec![TypeId::of::<C>()] }
324 fn register_columns(a: &mut Archetype) { a.register_column::<C>(); }
325 fn insert_into(self, a: &mut Archetype, tick: u32) {
326 a.columns.get_mut(&TypeId::of::<C>()).expect("col missing").push(self, tick);
327 }
328}
329
330macro_rules! impl_bundle {
331 ($($C:ident),+) => {
332 #[allow(non_snake_case)]
333 impl<$($C: Component),+> Bundle for ($($C,)+) {
334 fn type_ids() -> Vec<TypeId> {
335 let mut v = vec![$(TypeId::of::<$C>()),+]; v.sort(); v.dedup(); v
336 }
337 fn register_columns(a: &mut Archetype) { $(a.register_column::<$C>();)+ }
338 fn insert_into(self, a: &mut Archetype, tick: u32) {
339 let ($($C,)+) = self;
340 $(a.columns.get_mut(&TypeId::of::<$C>()).expect("col missing").push($C, tick);)+
341 }
342 }
343 };
344}
345impl_bundle!(A, B);
346impl_bundle!(A, B, C);
347impl_bundle!(A, B, C, D);
348impl_bundle!(A, B, C, D, E);
349impl_bundle!(A, B, C, D, E, F);
350impl_bundle!(A, B, C, D, E, F, G);
351impl_bundle!(A, B, C, D, E, F, G, H);
352
353#[derive(Default)]
359pub struct Resources {
360 map: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
361}
362
363impl Resources {
364 pub fn new() -> Self { Self::default() }
366 pub fn insert<T: 'static + Send + Sync>(&mut self, v: T) {
368 self.map.insert(TypeId::of::<T>(), Box::new(v));
369 }
370 pub fn get<T: 'static + Send + Sync>(&self) -> Option<&T> {
372 self.map.get(&TypeId::of::<T>())?.downcast_ref()
373 }
374 pub fn get_mut<T: 'static + Send + Sync>(&mut self) -> Option<&mut T> {
376 self.map.get_mut(&TypeId::of::<T>())?.downcast_mut()
377 }
378 pub fn remove<T: 'static + Send + Sync>(&mut self) -> Option<T> {
380 self.map.remove(&TypeId::of::<T>())
381 .and_then(|b| b.downcast::<T>().ok()).map(|b| *b)
382 }
383 pub fn contains<T: 'static + Send + Sync>(&self) -> bool {
385 self.map.contains_key(&TypeId::of::<T>())
386 }
387}
388
389pub struct Res<'a, T: 'static + Send + Sync> { inner: &'a T }
395impl<'a, T: 'static + Send + Sync> Res<'a, T> {
396 pub fn new(inner: &'a T) -> Self { Self { inner } }
398}
399impl<'a, T: 'static + Send + Sync> std::ops::Deref for Res<'a, T> {
400 type Target = T; fn deref(&self) -> &T { self.inner }
401}
402
403pub struct ResMut<'a, T: 'static + Send + Sync> { inner: &'a mut T }
405impl<'a, T: 'static + Send + Sync> ResMut<'a, T> {
406 pub fn new(inner: &'a mut T) -> Self { Self { inner } }
408}
409impl<'a, T: 'static + Send + Sync> std::ops::Deref for ResMut<'a, T> {
410 type Target = T; fn deref(&self) -> &T { self.inner }
411}
412impl<'a, T: 'static + Send + Sync> std::ops::DerefMut for ResMut<'a, T> {
413 fn deref_mut(&mut self) -> &mut T { self.inner }
414}
415
416pub struct Local<T: Default + 'static> { value: T }
422impl<T: Default + 'static> Local<T> {
423 pub fn new(value: T) -> Self { Self { value } }
425 pub fn default_value() -> Self { Self { value: T::default() } }
427}
428impl<T: Default + 'static> std::ops::Deref for Local<T> {
429 type Target = T; fn deref(&self) -> &T { &self.value }
430}
431impl<T: Default + 'static> std::ops::DerefMut for Local<T> {
432 fn deref_mut(&mut self) -> &mut T { &mut self.value }
433}
434
435pub struct Events<E: 'static + Send + Sync> {
441 buffers: [Vec<E>; 2],
442 current: usize,
443 event_count: usize,
444 start_event_count: usize,
445}
446
447impl<E: 'static + Send + Sync> Default for Events<E> {
448 fn default() -> Self {
449 Self { buffers: [Vec::new(), Vec::new()], current: 0, event_count: 0, start_event_count: 0 }
450 }
451}
452
453impl<E: 'static + Send + Sync> Events<E> {
454 pub fn new() -> Self { Self::default() }
456 pub fn send(&mut self, e: E) { self.buffers[self.current].push(e); self.event_count += 1; }
458 pub fn update(&mut self) {
460 let next = 1 - self.current;
461 self.buffers[next].clear();
462 self.start_event_count = self.event_count - self.buffers[self.current].len();
463 self.current = next;
464 }
465 pub fn get_reader(&self) -> EventCursor { EventCursor { last: self.event_count } }
467 pub fn get_reader_current(&self) -> EventCursor { EventCursor { last: self.start_event_count } }
469 pub fn read<'a>(&'a self, cursor: &mut EventCursor) -> impl Iterator<Item = &'a E> {
471 let start = cursor.last;
472 cursor.last = self.event_count;
473 let old = &self.buffers[1 - self.current];
474 let new = &self.buffers[self.current];
475 let base = self.start_event_count;
476 let sk0 = start.saturating_sub(base);
477 let tk0 = old.len().saturating_sub(sk0);
478 let sk1 = start.saturating_sub(base + old.len());
479 let tk1 = new.len().saturating_sub(sk1);
480 old.iter().skip(sk0).take(tk0).chain(new.iter().skip(sk1).take(tk1))
481 }
482 pub fn len(&self) -> usize { self.event_count }
484 pub fn is_empty(&self) -> bool { self.buffers[0].is_empty() && self.buffers[1].is_empty() }
486 pub fn clear(&mut self) { self.buffers[0].clear(); self.buffers[1].clear(); }
488}
489
490#[derive(Debug, Clone, Default)]
492pub struct EventCursor { last: usize }
493
494pub struct EventWriter<'a, E: 'static + Send + Sync> { events: &'a mut Events<E> }
496impl<'a, E: 'static + Send + Sync> EventWriter<'a, E> {
497 pub fn new(events: &'a mut Events<E>) -> Self { Self { events } }
499 pub fn send(&mut self, e: E) { self.events.send(e); }
501 pub fn send_batch(&mut self, it: impl IntoIterator<Item = E>) { for e in it { self.events.send(e); } }
503}
504
505pub struct EventReader<'a, E: 'static + Send + Sync> { events: &'a Events<E>, cursor: EventCursor }
507impl<'a, E: 'static + Send + Sync> EventReader<'a, E> {
508 pub fn new(events: &'a Events<E>) -> Self { Self { cursor: events.get_reader(), events } }
510 pub fn new_current(events: &'a Events<E>) -> Self { Self { cursor: events.get_reader_current(), events } }
512 pub fn read(&mut self) -> impl Iterator<Item = &E> { self.events.read(&mut self.cursor) }
514}
515
516enum Cmd {
521 Spawn(Box<dyn FnOnce(&mut World) + Send + Sync>),
522 Despawn(Entity),
523 Insert(Box<dyn FnOnce(&mut World) + Send + Sync>),
524 Remove(Entity, TypeId),
525 InsertRes(Box<dyn FnOnce(&mut World) + Send + Sync>),
526 RemoveRes(TypeId),
527}
528
529pub struct Commands { queue: Vec<Cmd> }
531impl Commands {
532 pub fn new() -> Self { Self { queue: Vec::new() } }
534 pub fn spawn<B: Bundle>(&mut self, b: B) {
536 self.queue.push(Cmd::Spawn(Box::new(move |w| { w.spawn(b); })));
537 }
538 pub fn despawn(&mut self, e: Entity) { self.queue.push(Cmd::Despawn(e)); }
540 pub fn insert<C: Component>(&mut self, e: Entity, c: C) {
542 self.queue.push(Cmd::Insert(Box::new(move |w| w.insert(e, c))));
543 }
544 pub fn remove<C: Component>(&mut self, e: Entity) {
546 self.queue.push(Cmd::Remove(e, TypeId::of::<C>()));
547 }
548 pub fn insert_resource<T: 'static + Send + Sync>(&mut self, v: T) {
550 self.queue.push(Cmd::InsertRes(Box::new(move |w| w.resources.insert(v))));
551 }
552 pub fn remove_resource<T: 'static + Send + Sync>(&mut self) {
554 self.queue.push(Cmd::RemoveRes(TypeId::of::<T>()));
555 }
556 pub fn apply(&mut self, world: &mut World) {
558 for cmd in self.queue.drain(..) {
559 match cmd {
560 Cmd::Spawn(f) => f(world),
561 Cmd::Despawn(e) => { world.despawn(e); }
562 Cmd::Insert(f) => f(world),
563 Cmd::Remove(e, tid) => world.remove_by_type_id(e, tid),
564 Cmd::InsertRes(f) => f(world),
565 Cmd::RemoveRes(tid) => { world.resources.map.remove(&tid); }
566 }
567 }
568 }
569 pub fn is_empty(&self) -> bool { self.queue.is_empty() }
571}
572impl Default for Commands { fn default() -> Self { Self::new() } }
573
574pub struct With<T: Component>(std::marker::PhantomData<T>);
580pub struct Without<T: Component>(std::marker::PhantomData<T>);
582pub struct Added<T: Component>(std::marker::PhantomData<T>);
584pub struct Changed<T: Component>(std::marker::PhantomData<T>);
586
587pub trait QueryFilter {
589 fn matches_archetype(arch: &Archetype) -> bool;
591}
592impl QueryFilter for () { fn matches_archetype(_: &Archetype) -> bool { true } }
593impl<T: Component> QueryFilter for With<T> {
594 fn matches_archetype(a: &Archetype) -> bool { a.contains(TypeId::of::<T>()) }
595}
596impl<T: Component> QueryFilter for Without<T> {
597 fn matches_archetype(a: &Archetype) -> bool { !a.contains(TypeId::of::<T>()) }
598}
599impl<A: QueryFilter, B: QueryFilter> QueryFilter for (A, B) {
600 fn matches_archetype(a: &Archetype) -> bool { A::matches_archetype(a) && B::matches_archetype(a) }
601}
602impl<A: QueryFilter, B: QueryFilter, C: QueryFilter> QueryFilter for (A, B, C) {
603 fn matches_archetype(a: &Archetype) -> bool {
604 A::matches_archetype(a) && B::matches_archetype(a) && C::matches_archetype(a)
605 }
606}
607
608pub struct Read<T: Component>(std::marker::PhantomData<T>);
614pub struct Write<T: Component>(std::marker::PhantomData<T>);
616pub struct OptionRead<T: Component>(std::marker::PhantomData<T>);
618
619pub trait WorldQuery: 'static {
621 type Item<'w>;
623 fn required_types() -> Vec<TypeId>;
625 fn matches(arch: &Archetype) -> bool;
627 unsafe fn fetch<'w>(arch: &'w Archetype, row: usize) -> Self::Item<'w>;
632}
633
634impl<T: Component> WorldQuery for Read<T> {
635 type Item<'w> = &'w T;
636 fn required_types() -> Vec<TypeId> { vec![TypeId::of::<T>()] }
637 fn matches(a: &Archetype) -> bool { a.contains(TypeId::of::<T>()) }
638 unsafe fn fetch<'w>(a: &'w Archetype, row: usize) -> &'w T {
639 a.columns[&TypeId::of::<T>()].column.get::<T>(row)
640 }
641}
642
643impl<T: Component> WorldQuery for Write<T> {
644 type Item<'w> = &'w mut T;
645 fn required_types() -> Vec<TypeId> { vec![TypeId::of::<T>()] }
646 fn matches(a: &Archetype) -> bool { a.contains(TypeId::of::<T>()) }
647 unsafe fn fetch<'w>(a: &'w Archetype, row: usize) -> &'w mut T {
648 let ptr = a.columns.get(&TypeId::of::<T>()).unwrap().column.get_ptr(row) as *mut T;
649 &mut *ptr
650 }
651}
652
653impl<T: Component> WorldQuery for OptionRead<T> {
654 type Item<'w> = Option<&'w T>;
655 fn required_types() -> Vec<TypeId> { vec![] }
656 fn matches(_: &Archetype) -> bool { true }
657 unsafe fn fetch<'w>(a: &'w Archetype, row: usize) -> Option<&'w T> {
658 a.columns.get(&TypeId::of::<T>()).map(|c| c.column.get::<T>(row))
659 }
660}
661
662impl WorldQuery for Entity {
663 type Item<'w> = Entity;
664 fn required_types() -> Vec<TypeId> { vec![] }
665 fn matches(_: &Archetype) -> bool { true }
666 unsafe fn fetch<'w>(a: &'w Archetype, row: usize) -> Entity { a.entities[row] }
667}
668
669macro_rules! impl_wq_tuple {
670 ($($Q:ident),+) => {
671 #[allow(non_snake_case)]
672 impl<$($Q: WorldQuery),+> WorldQuery for ($($Q,)+) {
673 type Item<'w> = ($($Q::Item<'w>,)+);
674 fn required_types() -> Vec<TypeId> {
675 let mut v = Vec::new(); $(v.extend($Q::required_types());)+ v.sort(); v.dedup(); v
676 }
677 fn matches(a: &Archetype) -> bool { $($Q::matches(a))&&+ }
678 unsafe fn fetch<'w>(a: &'w Archetype, row: usize) -> ($($Q::Item<'w>,)+) {
679 ($($Q::fetch(a, row),)+)
680 }
681 }
682 };
683}
684impl_wq_tuple!(A);
685impl_wq_tuple!(A, B);
686impl_wq_tuple!(A, B, C);
687impl_wq_tuple!(A, B, C, D);
688impl_wq_tuple!(A, B, C, D, E);
689impl_wq_tuple!(A, B, C, D, E, F);
690impl_wq_tuple!(A, B, C, D, E, F, G);
691impl_wq_tuple!(A, B, C, D, E, F, G, H);
692
693pub struct QueryIter<'w, Q: WorldQuery, F: QueryFilter> {
699 archetypes: &'w [Archetype],
700 arch_index: usize,
701 row: usize,
702 _q: std::marker::PhantomData<Q>,
703 _f: std::marker::PhantomData<F>,
704}
705impl<'w, Q: WorldQuery, F: QueryFilter> QueryIter<'w, Q, F> {
706 fn new(archetypes: &'w [Archetype]) -> Self {
707 Self { archetypes, arch_index: 0, row: 0, _q: std::marker::PhantomData, _f: std::marker::PhantomData }
708 }
709}
710impl<'w, Q: WorldQuery, F: QueryFilter> Iterator for QueryIter<'w, Q, F> {
711 type Item = Q::Item<'w>;
712 fn next(&mut self) -> Option<Self::Item> {
713 loop {
714 let arch = self.archetypes.get(self.arch_index)?;
715 if !Q::matches(arch) || !F::matches_archetype(arch) {
716 self.arch_index += 1; self.row = 0; continue;
717 }
718 if self.row >= arch.len() {
719 self.arch_index += 1; self.row = 0; continue;
720 }
721 let row = self.row; self.row += 1;
722 return Some(unsafe { Q::fetch(arch, row) });
723 }
724 }
725}
726
727pub struct EntityRef<'w> { arch: &'w Archetype, row: usize }
733impl<'w> EntityRef<'w> {
734 fn new(arch: &'w Archetype, row: usize) -> Self { Self { arch, row } }
735 pub fn entity(&self) -> Entity { self.arch.entities[self.row] }
737 pub fn get<T: Component>(&self) -> Option<&T> {
739 self.arch.columns.get(&TypeId::of::<T>()).map(|c| c.column.get::<T>(self.row))
740 }
741 pub fn has<T: Component>(&self) -> bool { self.arch.contains(TypeId::of::<T>()) }
743 pub fn component_types(&self) -> &[TypeId] { &self.arch.component_types }
745}
746
747pub struct EntityMut<'w> { arch: &'w mut Archetype, row: usize }
749impl<'w> EntityMut<'w> {
750 fn new(arch: &'w mut Archetype, row: usize) -> Self { Self { arch, row } }
751 pub fn entity(&self) -> Entity { self.arch.entities[self.row] }
753 pub fn get<T: Component>(&self) -> Option<&T> {
755 self.arch.columns.get(&TypeId::of::<T>()).map(|c| c.column.get::<T>(self.row))
756 }
757 pub fn get_mut<T: Component>(&mut self) -> Option<&mut T> {
759 self.arch.columns.get_mut(&TypeId::of::<T>()).map(|c| c.column.get_mut::<T>(self.row))
760 }
761 pub fn has<T: Component>(&self) -> bool { self.arch.contains(TypeId::of::<T>()) }
763}
764
765pub struct World {
771 archetypes: Vec<Archetype>,
772 archetype_index: HashMap<Vec<TypeId>, usize>,
773 entities: EntityAllocator,
774 pub resources: Resources,
776 events: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
777 tick: u32,
778}
779
780impl World {
781 pub fn new() -> Self {
783 Self {
784 archetypes: Vec::new(),
785 archetype_index: HashMap::new(),
786 entities: EntityAllocator::default(),
787 resources: Resources::new(),
788 events: HashMap::new(),
789 tick: 0,
790 }
791 }
792
793 pub fn tick(&self) -> u32 { self.tick }
795 pub fn increment_tick(&mut self) { self.tick = self.tick.wrapping_add(1); }
797
798 fn get_or_create_archetype(&mut self, mut types: Vec<TypeId>) -> usize {
801 types.sort(); types.dedup();
802 if let Some(&i) = self.archetype_index.get(&types) { return i; }
803 let id = ArchetypeId(self.archetypes.len() as u32);
804 let arch = Archetype::new(id, types.clone());
805 let i = self.archetypes.len();
806 self.archetypes.push(arch);
807 self.archetype_index.insert(types, i);
808 i
809 }
810
811 pub fn spawn<B: Bundle>(&mut self, bundle: B) -> Entity {
815 let types = B::type_ids();
816 let ai = self.get_or_create_archetype(types);
817 let entity = self.entities.alloc();
818 let tick = self.tick;
819 let arch = &mut self.archetypes[ai];
820 B::register_columns(arch);
821 let row = arch.entities.len();
822 arch.entities.push(entity);
823 bundle.insert_into(arch, tick);
824 self.entities.set_location(entity, EntityLocation { archetype_id: ArchetypeId(ai as u32), row });
825 entity
826 }
827
828 pub fn despawn(&mut self, entity: Entity) -> bool {
830 let loc = match self.entities.location(entity) { Some(l) => l, None => return false };
831 let ai = loc.archetype_id.0 as usize;
832 let swapped = self.archetypes[ai].swap_remove(loc.row);
833 self.entities.free(entity);
834 if let Some(se) = swapped {
835 self.entities.set_location(se, EntityLocation { archetype_id: loc.archetype_id, row: loc.row });
836 }
837 true
838 }
839
840 pub fn is_alive(&self, entity: Entity) -> bool { self.entities.is_alive(entity) }
842
843 pub fn insert<C: Component>(&mut self, entity: Entity, component: C) {
847 let loc = match self.entities.location(entity) { Some(l) => l, None => return };
848 let ai = loc.archetype_id.0 as usize;
849 if self.archetypes[ai].contains(TypeId::of::<C>()) {
851 let tick = self.tick;
852 let col = self.archetypes[ai].columns.get_mut(&TypeId::of::<C>()).unwrap();
853 *col.column.get_mut::<C>(loc.row) = component;
854 col.changed_ticks[loc.row] = tick;
855 return;
856 }
857 let mut new_types = self.archetypes[ai].component_types.clone();
859 new_types.push(TypeId::of::<C>());
860 let new_ai = self.get_or_create_archetype(new_types);
861 let tick = self.tick;
862 self.migrate_add::<C>(entity, loc, new_ai, component, tick);
863 }
864
865 fn migrate_add<C: Component>(
866 &mut self, entity: Entity, loc: EntityLocation, new_ai: usize, extra: C, tick: u32,
867 ) {
868 let old_ai = loc.archetype_id.0 as usize;
869 let row = loc.row;
870 let old_types: Vec<TypeId> = self.archetypes[old_ai].component_types.clone();
871 self.ensure_cols(old_ai, new_ai, &old_types);
873 if !self.archetypes[new_ai].columns.contains_key(&TypeId::of::<C>()) {
874 self.archetypes[new_ai].register_column::<C>();
875 }
876 let new_row = self.archetypes[new_ai].entities.len();
877 for &tid in &old_types {
878 Self::copy_row(&mut self.archetypes, old_ai, new_ai, tid, row, tick);
879 }
880 self.archetypes[new_ai].columns.get_mut(&TypeId::of::<C>()).unwrap().push(extra, tick);
881 self.archetypes[new_ai].entities.push(entity);
882 let swapped = self.archetypes[old_ai].swap_remove(row);
883 self.entities.set_location(entity, EntityLocation { archetype_id: ArchetypeId(new_ai as u32), row: new_row });
884 if let Some(se) = swapped {
885 self.entities.set_location(se, EntityLocation { archetype_id: loc.archetype_id, row });
886 }
887 }
888
889 fn ensure_cols(&mut self, src: usize, dst: usize, types: &[TypeId]) {
890 for &tid in types {
891 if self.archetypes[dst].columns.contains_key(&tid) { continue; }
892 let s = &self.archetypes[src].columns[&tid];
893 let nc = ComponentStorage {
894 column: AnyVec {
895 type_id: s.column.type_id, len: 0, data: Vec::new(),
896 element_size: s.column.element_size,
897 element_align: s.column.element_align,
898 drop_fn: s.column.drop_fn, clone_fn: s.column.clone_fn,
899 },
900 added_ticks: Vec::new(), changed_ticks: Vec::new(),
901 };
902 self.archetypes[dst].columns.insert(tid, nc);
903 }
904 }
905
906 fn copy_row(archetypes: &mut Vec<Archetype>, src: usize, dst: usize, tid: TypeId, row: usize, tick: u32) {
907 let (sa, da) = if src < dst {
908 let (l, r) = archetypes.split_at_mut(dst); (&l[src], &mut r[0])
909 } else {
910 let (l, r) = archetypes.split_at_mut(src); (&r[0], &mut l[dst])
911 };
912 if let (Some(sc), Some(dc)) = (sa.columns.get(&tid), da.columns.get_mut(&tid)) {
913 sc.clone_row_into(row, dc, tick);
914 }
915 }
916
917 pub fn remove<C: Component>(&mut self, entity: Entity) {
919 self.remove_by_type_id(entity, TypeId::of::<C>());
920 }
921
922 pub(crate) fn remove_by_type_id(&mut self, entity: Entity, tid: TypeId) {
924 let loc = match self.entities.location(entity) { Some(l) => l, None => return };
925 let old_ai = loc.archetype_id.0 as usize;
926 if !self.archetypes[old_ai].contains(tid) { return; }
927 let row = loc.row;
928 let new_types: Vec<TypeId> = self.archetypes[old_ai].component_types.iter()
929 .copied().filter(|&t| t != tid).collect();
930 let new_ai = self.get_or_create_archetype(new_types.clone());
931 let tick = self.tick;
932 let old_types: Vec<TypeId> = self.archetypes[old_ai].component_types.clone();
933 self.ensure_cols(old_ai, new_ai, &new_types);
934 let new_row = self.archetypes[new_ai].entities.len();
935 for &t in &old_types {
936 if t == tid { continue; }
937 Self::copy_row(&mut self.archetypes, old_ai, new_ai, t, row, tick);
938 }
939 self.archetypes[new_ai].entities.push(entity);
940 let swapped = self.archetypes[old_ai].swap_remove(row);
941 self.entities.set_location(entity, EntityLocation { archetype_id: ArchetypeId(new_ai as u32), row: new_row });
942 if let Some(se) = swapped {
943 self.entities.set_location(se, EntityLocation { archetype_id: loc.archetype_id, row });
944 }
945 }
946
947 pub fn get<C: Component>(&self, entity: Entity) -> Option<&C> {
951 let loc = self.entities.location(entity)?;
952 self.archetypes[loc.archetype_id.0 as usize]
953 .columns.get(&TypeId::of::<C>()).map(|c| c.column.get::<C>(loc.row))
954 }
955
956 pub fn get_mut<C: Component>(&mut self, entity: Entity) -> Option<&mut C> {
958 let loc = self.entities.location(entity)?;
959 let tick = self.tick;
960 let arch = &mut self.archetypes[loc.archetype_id.0 as usize];
961 arch.columns.get_mut(&TypeId::of::<C>()).map(|c| {
962 c.changed_ticks[loc.row] = tick;
963 c.column.get_mut::<C>(loc.row)
964 })
965 }
966
967 pub fn entity_ref(&self, entity: Entity) -> Option<EntityRef<'_>> {
969 let loc = self.entities.location(entity)?;
970 Some(EntityRef::new(&self.archetypes[loc.archetype_id.0 as usize], loc.row))
971 }
972
973 pub fn entity_mut(&mut self, entity: Entity) -> Option<EntityMut<'_>> {
975 let loc = self.entities.location(entity)?;
976 let ai = loc.archetype_id.0 as usize;
977 Some(EntityMut::new(&mut self.archetypes[ai], loc.row))
978 }
979
980 pub fn query<Q: WorldQuery, F: QueryFilter>(&self) -> QueryIter<'_, Q, F> {
984 QueryIter::new(&self.archetypes)
985 }
986
987 pub fn query_all<Q: WorldQuery>(&self) -> QueryIter<'_, Q, ()> {
989 QueryIter::new(&self.archetypes)
990 }
991
992 pub fn query_single<Q: WorldQuery>(&self) -> Option<Q::Item<'_>> {
994 let mut it = self.query::<Q, ()>();
995 let first = it.next()?;
996 if it.next().is_some() { return None; }
997 Some(first)
998 }
999
1000 pub fn insert_resource<T: 'static + Send + Sync>(&mut self, v: T) { self.resources.insert(v); }
1004 pub fn resource<T: 'static + Send + Sync>(&self) -> Option<Res<'_, T>> {
1006 self.resources.get::<T>().map(Res::new)
1007 }
1008 pub fn resource_mut<T: 'static + Send + Sync>(&mut self) -> Option<ResMut<'_, T>> {
1010 self.resources.get_mut::<T>().map(ResMut::new)
1011 }
1012 pub fn remove_resource<T: 'static + Send + Sync>(&mut self) -> Option<T> { self.resources.remove::<T>() }
1014
1015 pub fn add_event<E: 'static + Send + Sync>(&mut self) {
1019 self.events.entry(TypeId::of::<Events<E>>())
1020 .or_insert_with(|| Box::new(Events::<E>::new()));
1021 }
1022 pub fn events<E: 'static + Send + Sync>(&self) -> Option<&Events<E>> {
1024 self.events.get(&TypeId::of::<Events<E>>())?.downcast_ref()
1025 }
1026 pub fn events_mut<E: 'static + Send + Sync>(&mut self) -> Option<&mut Events<E>> {
1028 self.events.get_mut(&TypeId::of::<Events<E>>())?.downcast_mut()
1029 }
1030 pub fn send_event<E: 'static + Send + Sync>(&mut self, event: E) {
1032 self.events.entry(TypeId::of::<Events<E>>())
1033 .or_insert_with(|| Box::new(Events::<E>::new()))
1034 .downcast_mut::<Events<E>>().unwrap().send(event);
1035 }
1036
1037 pub fn entities(&self) -> impl Iterator<Item = Entity> + '_ {
1041 self.archetypes.iter().flat_map(|a| a.entities.iter().copied())
1042 }
1043 pub fn entity_count(&self) -> usize { self.archetypes.iter().map(|a| a.len()).sum() }
1045 pub fn archetype_count(&self) -> usize { self.archetypes.len() }
1047}
1048
1049impl Default for World { fn default() -> Self { Self::new() } }
1050
1051pub trait SystemParam: Sized {
1057 type State: Default + Send + Sync + 'static;
1059 fn init_state(world: &mut World) -> Self::State;
1061}
1062
1063pub trait System: Send + Sync + 'static {
1069 fn run(&mut self, world: &mut World);
1071 fn name(&self) -> &str;
1073}
1074
1075pub struct FunctionSystem<F: FnMut(&mut World) + Send + Sync + 'static> { f: F, name: String }
1077impl<F: FnMut(&mut World) + Send + Sync + 'static> FunctionSystem<F> {
1078 pub fn new(name: impl Into<String>, f: F) -> Self { Self { f, name: name.into() } }
1080}
1081impl<F: FnMut(&mut World) + Send + Sync + 'static> System for FunctionSystem<F> {
1082 fn run(&mut self, w: &mut World) { (self.f)(w); }
1083 fn name(&self) -> &str { &self.name }
1084}
1085
1086pub fn into_system(name: impl Into<String>, f: impl FnMut(&mut World) + Send + Sync + 'static) -> Box<dyn System> {
1088 Box::new(FunctionSystem::new(name, f))
1089}
1090
1091#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1097pub struct SystemLabel(pub String);
1098impl SystemLabel {
1099 pub fn new(s: impl Into<String>) -> Self { Self(s.into()) }
1101}
1102impl<S: Into<String>> From<S> for SystemLabel { fn from(s: S) -> Self { Self(s.into()) } }
1103
1104pub type RunCondition = Box<dyn Fn(&World) -> bool + Send + Sync>;
1106
1107struct SystemEntry { system: Box<dyn System>, label: Option<SystemLabel>, run_if: Option<RunCondition> }
1108
1109pub struct Schedule { systems: Vec<SystemEntry> }
1111impl Schedule {
1112 pub fn new() -> Self { Self { systems: Vec::new() } }
1114 pub fn add_system(&mut self, s: Box<dyn System>) -> &mut Self {
1116 self.systems.push(SystemEntry { system: s, label: None, run_if: None }); self
1117 }
1118 pub fn add_system_with_label(&mut self, s: Box<dyn System>, label: impl Into<SystemLabel>) -> &mut Self {
1120 self.systems.push(SystemEntry { system: s, label: Some(label.into()), run_if: None }); self
1121 }
1122 pub fn add_system_with_condition(
1124 &mut self, s: Box<dyn System>,
1125 cond: impl Fn(&World) -> bool + Send + Sync + 'static,
1126 ) -> &mut Self {
1127 self.systems.push(SystemEntry { system: s, label: None, run_if: Some(Box::new(cond)) }); self
1128 }
1129 pub fn add_system_full(
1131 &mut self, s: Box<dyn System>, label: impl Into<SystemLabel>,
1132 cond: impl Fn(&World) -> bool + Send + Sync + 'static,
1133 ) -> &mut Self {
1134 self.systems.push(SystemEntry { system: s, label: Some(label.into()), run_if: Some(Box::new(cond)) }); self
1135 }
1136 pub fn remove_system(&mut self, label: &SystemLabel) {
1138 self.systems.retain(|e| e.label.as_ref() != Some(label));
1139 }
1140 pub fn system_count(&self) -> usize { self.systems.len() }
1142 pub fn run(&mut self, world: &mut World) {
1144 world.increment_tick();
1145 for e in &mut self.systems {
1146 if e.run_if.as_ref().map(|c| c(world)).unwrap_or(true) { e.system.run(world); }
1147 }
1148 }
1149 pub fn labels(&self) -> Vec<Option<&SystemLabel>> { self.systems.iter().map(|e| e.label.as_ref()).collect() }
1151}
1152impl Default for Schedule { fn default() -> Self { Self::new() } }
1153
1154pub fn was_added<C: Component>(w: &World, entity: Entity, since: u32) -> bool {
1160 let loc = match w.entities.location(entity) { Some(l) => l, None => return false };
1161 w.archetypes[loc.archetype_id.0 as usize].columns
1162 .get(&TypeId::of::<C>()).map(|c| c.added_ticks[loc.row] > since).unwrap_or(false)
1163}
1164
1165pub fn was_changed<C: Component>(w: &World, entity: Entity, since: u32) -> bool {
1167 let loc = match w.entities.location(entity) { Some(l) => l, None => return false };
1168 w.archetypes[loc.archetype_id.0 as usize].columns
1169 .get(&TypeId::of::<C>()).map(|c| c.changed_ticks[loc.row] > since).unwrap_or(false)
1170}
1171
1172pub fn query_added<C: Component>(w: &World, since: u32) -> impl Iterator<Item = Entity> + '_ {
1174 w.archetypes.iter().flat_map(move |arch| {
1175 if !arch.contains(TypeId::of::<C>()) { return vec![]; }
1176 let col = &arch.columns[&TypeId::of::<C>()];
1177 arch.entities.iter().enumerate()
1178 .filter(move |(r, _)| col.added_ticks[*r] > since)
1179 .map(|(_, &e)| e).collect::<Vec<_>>()
1180 })
1181}
1182
1183pub fn query_changed<C: Component>(w: &World, since: u32) -> impl Iterator<Item = Entity> + '_ {
1185 w.archetypes.iter().flat_map(move |arch| {
1186 if !arch.contains(TypeId::of::<C>()) { return vec![]; }
1187 let col = &arch.columns[&TypeId::of::<C>()];
1188 arch.entities.iter().enumerate()
1189 .filter(move |(r, _)| col.changed_ticks[*r] > since)
1190 .map(|(_, &e)| e).collect::<Vec<_>>()
1191 })
1192}
1193
1194pub mod prelude {
1200 pub use super::{
1201 Component, Entity, World, Bundle,
1202 Archetype, ArchetypeId, EntityRef, EntityMut,
1203 Resources, Res, ResMut, Local,
1204 Events, EventCursor, EventWriter, EventReader,
1205 Commands, With, Without, Added, Changed,
1206 Read, Write, OptionRead,
1207 WorldQuery, QueryFilter, QueryIter,
1208 System, SystemParam, FunctionSystem, into_system,
1209 Schedule, SystemLabel,
1210 was_added, was_changed, query_added, query_changed,
1211 };
1212}
1213
1214#[cfg(test)]
1219mod tests {
1220 use super::*;
1221
1222 #[derive(Debug, Clone, PartialEq)] struct Position { x: f32, y: f32 }
1223 impl Component for Position {}
1224
1225 #[derive(Debug, Clone, PartialEq)] struct Velocity { dx: f32, dy: f32 }
1226 impl Component for Velocity {}
1227
1228 #[derive(Debug, Clone, PartialEq)] struct Health(f32);
1229 impl Component for Health {}
1230
1231 #[derive(Debug, Clone)] struct Tag; impl Component for Tag {}
1232 #[derive(Debug, Clone)] struct Enemy; impl Component for Enemy {}
1233 #[derive(Debug, Clone)] struct Player; impl Component for Player {}
1234
1235 #[test] fn test_spawn_alive() {
1237 let mut w = World::new();
1238 let e = w.spawn(Position { x: 1.0, y: 2.0 });
1239 assert!(w.is_alive(e)); assert_eq!(w.entity_count(), 1);
1240 }
1241 #[test] fn test_despawn() {
1242 let mut w = World::new();
1243 let e = w.spawn(Position { x: 0.0, y: 0.0 });
1244 assert!(w.despawn(e)); assert!(!w.is_alive(e)); assert_eq!(w.entity_count(), 0);
1245 }
1246 #[test] fn test_despawn_nonexistent() {
1247 let mut w = World::new(); assert!(!w.despawn(Entity::from_raw(99, 99)));
1248 }
1249 #[test] fn test_null_entity() {
1250 assert!(Entity::null().is_null()); assert!(!Entity::from_raw(0,0).is_null());
1251 }
1252 #[test] fn test_generation_reuse() {
1253 let mut w = World::new();
1254 let e1 = w.spawn(Position { x: 0.0, y: 0.0 }); w.despawn(e1);
1255 let e2 = w.spawn(Position { x: 1.0, y: 0.0 });
1256 assert_eq!(e1.index, e2.index); assert_ne!(e1.generation, e2.generation);
1257 assert!(!w.is_alive(e1)); assert!(w.is_alive(e2));
1258 }
1259 #[test] fn test_entity_display() { assert_eq!(format!("{}", Entity::from_raw(5,2)), "Entity(5v2)"); }
1260
1261 #[test] fn test_get_component() {
1263 let mut w = World::new(); let e = w.spawn(Position { x: 3.0, y: 4.0 });
1264 assert_eq!(w.get::<Position>(e).unwrap().x, 3.0);
1265 }
1266 #[test] fn test_get_mut_component() {
1267 let mut w = World::new(); let e = w.spawn(Position { x: 0.0, y: 0.0 });
1268 w.get_mut::<Position>(e).unwrap().x = 10.0;
1269 assert_eq!(w.get::<Position>(e).unwrap().x, 10.0);
1270 }
1271 #[test] fn test_missing_component_none() {
1272 let mut w = World::new(); let e = w.spawn(Position { x: 0.0, y: 0.0 });
1273 assert!(w.get::<Velocity>(e).is_none());
1274 }
1275 #[test] fn test_entity_ref() {
1276 let mut w = World::new(); let e = w.spawn((Position { x: 1.0, y: 2.0 }, Health(100.0)));
1277 let er = w.entity_ref(e).unwrap();
1278 assert_eq!(er.get::<Position>().unwrap(), &Position { x: 1.0, y: 2.0 });
1279 assert!(er.has::<Position>()); assert!(!er.has::<Velocity>());
1280 }
1281 #[test] fn test_entity_mut() {
1282 let mut w = World::new(); let e = w.spawn(Health(50.0));
1283 w.entity_mut(e).unwrap().get_mut::<Health>().unwrap().0 = 75.0;
1284 assert_eq!(w.get::<Health>(e).unwrap().0, 75.0);
1285 }
1286
1287 #[test] fn test_spawn_tuple_bundle() {
1289 let mut w = World::new();
1290 let e = w.spawn((Position { x: 1.0, y: 0.0 }, Velocity { dx: 0.5, dy: 0.0 }, Health(100.0)));
1291 assert!(w.get::<Position>(e).is_some()); assert!(w.get::<Velocity>(e).is_some()); assert!(w.get::<Health>(e).is_some());
1292 }
1293 #[test] fn test_same_archetype() {
1294 let mut w = World::new();
1295 let e1 = w.spawn((Position { x: 0.0, y: 0.0 }, Velocity { dx: 1.0, dy: 0.0 }));
1296 let e2 = w.spawn((Position { x: 5.0, y: 5.0 }, Velocity { dx: -1.0, dy: 0.0 }));
1297 assert_eq!(w.archetype_count(), 1);
1298 assert_eq!(w.get::<Position>(e1).unwrap().x, 0.0);
1299 assert_eq!(w.get::<Position>(e2).unwrap().x, 5.0);
1300 }
1301
1302 #[test] fn test_insert_new_component() {
1304 let mut w = World::new(); let e = w.spawn(Position { x: 0.0, y: 0.0 });
1305 w.insert(e, Velocity { dx: 1.0, dy: 0.0 });
1306 assert!(w.get::<Velocity>(e).is_some()); assert!(w.get::<Position>(e).is_some());
1307 }
1308 #[test] fn test_insert_replaces() {
1309 let mut w = World::new(); let e = w.spawn(Health(100.0));
1310 w.insert(e, Health(50.0)); assert_eq!(w.get::<Health>(e).unwrap().0, 50.0);
1311 }
1312 #[test] fn test_remove_component() {
1313 let mut w = World::new();
1314 let e = w.spawn((Position { x: 0.0, y: 0.0 }, Velocity { dx: 1.0, dy: 0.0 }));
1315 w.remove::<Velocity>(e);
1316 assert!(w.get::<Velocity>(e).is_none()); assert!(w.get::<Position>(e).is_some());
1317 }
1318 #[test] fn test_remove_missing_noop() {
1319 let mut w = World::new(); let e = w.spawn(Position { x: 0.0, y: 0.0 });
1320 w.remove::<Velocity>(e); assert!(w.is_alive(e));
1321 }
1322 #[test] fn test_insert_remove_roundtrip() {
1323 let mut w = World::new(); let e = w.spawn(Position { x: 1.0, y: 2.0 });
1324 w.insert(e, Health(99.0)); assert_eq!(w.get::<Health>(e).unwrap().0, 99.0);
1325 w.remove::<Health>(e); assert!(w.get::<Health>(e).is_none());
1326 assert_eq!(w.get::<Position>(e).unwrap().x, 1.0);
1327 }
1328
1329 #[test] fn test_query_single_component() {
1331 let mut w = World::new();
1332 w.spawn(Position { x: 1.0, y: 0.0 }); w.spawn(Position { x: 2.0, y: 0.0 }); w.spawn(Position { x: 3.0, y: 0.0 });
1333 assert_eq!(w.query::<Read<Position>, ()>().count(), 3);
1334 }
1335 #[test] fn test_query_tuple() {
1336 let mut w = World::new();
1337 w.spawn((Position { x: 0.0, y: 0.0 }, Velocity { dx: 1.0, dy: 0.0 }));
1338 w.spawn(Position { x: 5.0, y: 0.0 });
1339 assert_eq!(w.query::<(Read<Position>, Read<Velocity>), ()>().count(), 1);
1340 }
1341 #[test] fn test_query_with_filter() {
1342 let mut w = World::new();
1343 w.spawn((Position { x: 0.0, y: 0.0 }, Tag)); w.spawn(Position { x: 1.0, y: 0.0 });
1344 assert_eq!(w.query::<Read<Position>, With<Tag>>().count(), 1);
1345 }
1346 #[test] fn test_query_without_filter() {
1347 let mut w = World::new();
1348 w.spawn((Position { x: 0.0, y: 0.0 }, Enemy));
1349 w.spawn((Position { x: 1.0, y: 0.0 }, Player));
1350 w.spawn(Position { x: 2.0, y: 0.0 });
1351 assert_eq!(w.query::<Read<Position>, Without<Enemy>>().count(), 2);
1352 }
1353 #[test] fn test_query_option_read() {
1354 let mut w = World::new();
1355 w.spawn((Position { x: 0.0, y: 0.0 }, Health(100.0))); w.spawn(Position { x: 1.0, y: 0.0 });
1356 let r: Vec<_> = w.query::<(Read<Position>, OptionRead<Health>), ()>().collect();
1357 assert_eq!(r.len(), 2); assert_eq!(r.iter().filter(|(_, h)| h.is_some()).count(), 1);
1358 }
1359 #[test] fn test_query_entity() {
1360 let mut w = World::new();
1361 let e1 = w.spawn(Position { x: 0.0, y: 0.0 }); let e2 = w.spawn(Position { x: 1.0, y: 0.0 });
1362 let es: Vec<Entity> = w.query::<Entity, ()>().collect();
1363 assert!(es.contains(&e1)); assert!(es.contains(&e2));
1364 }
1365 #[test] fn test_query_mutable() {
1366 let mut w = World::new();
1367 w.spawn(Position { x: 0.0, y: 0.0 }); w.spawn(Position { x: 1.0, y: 0.0 });
1368 for p in w.query::<Write<Position>, ()>() { p.x += 10.0; }
1369 assert!(w.query::<Read<Position>, ()>().all(|p| p.x >= 10.0));
1370 }
1371 #[test] fn test_query_single() {
1372 let mut w = World::new(); w.spawn(Player);
1373 assert!(w.query_single::<Read<Player>>().is_some());
1374 }
1375 #[test] fn test_query_single_none_multiple() {
1376 let mut w = World::new(); w.spawn(Player); w.spawn(Player);
1377 assert!(w.query_single::<Read<Player>>().is_none());
1378 }
1379
1380 #[test] fn test_resource_insert_get() {
1382 let mut w = World::new(); w.insert_resource(42u32);
1383 assert_eq!(*w.resource::<u32>().unwrap(), 42);
1384 }
1385 #[test] fn test_resource_mut() {
1386 let mut w = World::new(); w.insert_resource(0u32);
1387 *w.resource_mut::<u32>().unwrap() = 99;
1388 assert_eq!(*w.resource::<u32>().unwrap(), 99);
1389 }
1390 #[test] fn test_resource_remove() {
1391 let mut w = World::new(); w.insert_resource(42u32);
1392 assert_eq!(w.remove_resource::<u32>(), Some(42));
1393 assert!(w.resource::<u32>().is_none());
1394 }
1395 #[test] fn test_resources_standalone() {
1396 let mut r = Resources::new(); r.insert(42u32);
1397 assert!(r.contains::<u32>()); assert!(!r.contains::<i32>());
1398 r.remove::<u32>(); assert!(!r.contains::<u32>());
1399 }
1400
1401 #[test] fn test_commands_spawn() {
1403 let mut w = World::new(); let mut c = Commands::new();
1404 c.spawn(Position { x: 7.0, y: 8.0 }); c.apply(&mut w);
1405 assert_eq!(w.query_single::<Read<Position>>().unwrap().x, 7.0);
1406 }
1407 #[test] fn test_commands_despawn() {
1408 let mut w = World::new(); let e = w.spawn(Position { x: 0.0, y: 0.0 });
1409 let mut c = Commands::new(); c.despawn(e); c.apply(&mut w); assert!(!w.is_alive(e));
1410 }
1411 #[test] fn test_commands_insert() {
1412 let mut w = World::new(); let e = w.spawn(Position { x: 0.0, y: 0.0 });
1413 let mut c = Commands::new(); c.insert(e, Health(50.0)); c.apply(&mut w);
1414 assert_eq!(w.get::<Health>(e).unwrap().0, 50.0);
1415 }
1416 #[test] fn test_commands_remove() {
1417 let mut w = World::new(); let e = w.spawn((Position { x: 0.0, y: 0.0 }, Health(100.0)));
1418 let mut c = Commands::new(); c.remove::<Health>(e); c.apply(&mut w);
1419 assert!(w.get::<Health>(e).is_none());
1420 }
1421 #[test] fn test_commands_insert_resource() {
1422 let mut w = World::new(); let mut c = Commands::new();
1423 c.insert_resource(100i32); c.apply(&mut w);
1424 assert_eq!(*w.resource::<i32>().unwrap(), 100);
1425 }
1426
1427 #[derive(Debug, Clone, PartialEq)] struct Dmg { amount: f32 }
1429 #[test] fn test_events_send_read() {
1430 let mut ev: Events<Dmg> = Events::new(); let mut cur = ev.get_reader_current();
1431 ev.send(Dmg { amount: 10.0 }); ev.send(Dmg { amount: 20.0 });
1432 let r: Vec<_> = ev.read(&mut cur).collect();
1433 assert_eq!(r.len(), 2); assert_eq!(r[0].amount, 10.0);
1434 }
1435 #[test] fn test_events_update_clears() {
1436 let mut ev: Events<Dmg> = Events::new(); ev.send(Dmg { amount: 5.0 });
1437 ev.update(); ev.update(); assert!(ev.is_empty());
1438 }
1439 #[test] fn test_event_writer_reader() {
1440 let mut ev: Events<Dmg> = Events::new();
1441 EventWriter::new(&mut ev).send(Dmg { amount: 42.0 });
1442 let mut reader = EventReader::new_current(&ev);
1443 let r: Vec<_> = reader.read().collect();
1444 assert_eq!(r.len(), 1); assert_eq!(r[0].amount, 42.0);
1445 }
1446 #[test] fn test_world_events() {
1447 let mut w = World::new(); w.add_event::<Dmg>();
1448 w.send_event(Dmg { amount: 99.0 }); assert!(!w.events::<Dmg>().unwrap().is_empty());
1449 }
1450
1451 #[test] fn test_schedule_runs_systems() {
1453 let mut w = World::new(); w.insert_resource(0u32);
1454 let mut s = Schedule::new();
1455 s.add_system(into_system("inc", |w| { *w.resource_mut::<u32>().unwrap() += 1; }));
1456 s.run(&mut w); s.run(&mut w); assert_eq!(*w.resource::<u32>().unwrap(), 2);
1457 }
1458 #[test] fn test_schedule_run_condition() {
1459 let mut w = World::new(); w.insert_resource(0u32); w.insert_resource(false);
1460 let mut s = Schedule::new();
1461 s.add_system_with_condition(
1462 into_system("g", |w| { *w.resource_mut::<u32>().unwrap() += 1; }),
1463 |w| *w.resource::<bool>().unwrap(),
1464 );
1465 s.run(&mut w); assert_eq!(*w.resource::<u32>().unwrap(), 0);
1466 *w.resource_mut::<bool>().unwrap() = true;
1467 s.run(&mut w); assert_eq!(*w.resource::<u32>().unwrap(), 1);
1468 }
1469 #[test] fn test_schedule_remove_label() {
1470 let mut s = Schedule::new();
1471 s.add_system_with_label(into_system("n", |_|{}), "lbl");
1472 assert_eq!(s.system_count(), 1);
1473 s.remove_system(&SystemLabel::new("lbl"));
1474 assert_eq!(s.system_count(), 0);
1475 }
1476 #[test] fn test_schedule_tick_increment() {
1477 let mut w = World::new(); let mut s = Schedule::new();
1478 s.run(&mut w); assert_eq!(w.tick(), 1); s.run(&mut w); assert_eq!(w.tick(), 2);
1479 }
1480
1481 #[test] fn test_was_added() {
1483 let mut w = World::new(); w.increment_tick();
1484 let e = w.spawn(Health(100.0));
1485 assert!(was_added::<Health>(&w, e, 0)); assert!(!was_added::<Health>(&w, e, 1));
1486 }
1487 #[test] fn test_was_changed() {
1488 let mut w = World::new(); w.increment_tick();
1489 let e = w.spawn(Health(100.0)); w.increment_tick();
1490 w.get_mut::<Health>(e).unwrap().0 = 50.0;
1491 assert!(was_changed::<Health>(&w, e, 1)); assert!(!was_changed::<Health>(&w, e, 2));
1492 }
1493 #[test] fn test_query_added() {
1494 let mut w = World::new(); w.increment_tick();
1495 let e1 = w.spawn(Health(100.0)); w.increment_tick(); let _e2 = w.spawn(Health(50.0));
1496 let added: Vec<_> = query_added::<Health>(&w, 1).collect();
1497 assert_eq!(added.len(), 1); assert!(!added.contains(&e1));
1498 }
1499
1500 #[test] fn test_local() {
1502 let mut l: Local<u32> = Local::default_value();
1503 assert_eq!(*l, 0); *l += 5; assert_eq!(*l, 5);
1504 }
1505
1506 #[test] fn test_swap_remove_updates_location() {
1508 let mut w = World::new();
1509 let e1 = w.spawn(Position { x: 1.0, y: 0.0 });
1510 let _e2 = w.spawn(Position { x: 2.0, y: 0.0 });
1511 let e3 = w.spawn(Position { x: 3.0, y: 0.0 });
1512 w.despawn(e1);
1513 assert!(w.is_alive(e3)); assert_eq!(w.get::<Position>(e3).unwrap().x, 3.0);
1514 }
1515 #[test] fn test_spawn_many() {
1516 let mut w = World::new();
1517 for i in 0..1000u32 { w.spawn(Position { x: i as f32, y: 0.0 }); }
1518 assert_eq!(w.entity_count(), 1000);
1519 assert_eq!(w.query::<Read<Position>, ()>().count(), 1000);
1520 }
1521 #[test] fn test_world_default() { let w = World::default(); assert_eq!(w.entity_count(), 0); }
1522 #[test] fn test_multiple_archetypes() {
1523 let mut w = World::new();
1524 w.spawn(Position { x: 0.0, y: 0.0 }); w.spawn(Health(100.0));
1525 w.spawn((Position { x: 1.0, y: 0.0 }, Health(50.0)));
1526 assert_eq!(w.archetype_count(), 3);
1527 assert_eq!(w.query::<Read<Position>, ()>().count(), 2);
1528 assert_eq!(w.query::<Read<Health>, ()>().count(), 2);
1529 assert_eq!(w.query::<(Read<Position>, Read<Health>), ()>().count(), 1);
1530 }
1531 #[test] fn test_entity_count_after_despawn() {
1532 let mut w = World::new();
1533 let es: Vec<Entity> = (0..10).map(|i| w.spawn(Health(i as f32))).collect();
1534 for &e in &es[..5] { w.despawn(e); }
1535 assert_eq!(w.entity_count(), 5);
1536 }
1537}