1use super::{
2 cache::{CacheStorage, RefreshCacheStorage},
3 cmd::Command,
4 ent::{
5 component::Components,
6 entity::{ContainEntity, Entity, EntityId, EntityIndex, EntityKeyRef},
7 storage::{AsEntityReg, EntityContainer, EntityReg, EntityStorage},
8 },
9 post::{Commander, Post},
10 resource::{Resource, ResourceDesc, ResourceIndex, ResourceKey, ResourceStorage},
11 sched::{
12 comm::{command_channel, CommandReceiver, CommandSender},
13 ctrl::Scheduler,
14 },
15 sys::{
16 storage::SystemStorage,
17 system::{
18 FnOnceSystem, InsertPos, PoisonedSystem, System, SystemData, SystemDesc, SystemFlags,
19 SystemId, Tick,
20 },
21 },
22 worker::Work,
23 DynResult, EcsError,
24};
25use crate::util::{macros::debug_format, Or, With, WithResult};
26use my_ecs_macros::repeat_macro;
27use std::{
28 any::Any,
29 error::Error,
30 fmt::Debug,
31 hash::{BuildHasher, RandomState},
32 marker::PhantomData,
33 mem,
34 ops::{Deref, DerefMut},
35 ptr::NonNull,
36 rc::Rc,
37 sync::Arc,
38 thread,
39};
40
41pub mod prelude {
42 pub use super::{Ecs, EcsApp, EcsEntry, EcsExt, HelpExecuteManyCommands, LeakedEcsApp};
43}
44
45pub trait EcsEntry {
52 fn add_systems<T, Systems>(&mut self, descs: T) -> WithResult<&mut Self, (), EcsError>
69 where
70 T: HelpAddManySystems<Systems>,
71 {
72 descs.add_systems(self)
73 }
74
75 fn add_system<T, Sys>(
89 &mut self,
90 desc: T,
91 ) -> WithResult<&mut Self, SystemId, EcsError<SystemDesc<Sys>>>
92 where
93 T: Into<SystemDesc<Sys>>,
94 Sys: System;
95
96 fn add_once_systems<T, Once>(&mut self, descs: T) -> WithResult<&mut Self, (), EcsError>
113 where
114 T: HelpAddManyOnce<Once>,
115 {
116 descs.add_once_systems(self)
117 }
118
119 fn add_once_system<T, Req, F>(
134 &mut self,
135 sys: T,
136 ) -> WithResult<&mut Self, SystemId, EcsError<SystemDesc<FnOnceSystem<Req, F>>>>
137 where
138 T: Into<FnOnceSystem<Req, F>>,
139 FnOnceSystem<Req, F>: System;
140
141 fn unregister_system(&mut self, sid: SystemId) -> WithResult<&mut Self, (), EcsError>;
158
159 fn activate_system(
182 &mut self,
183 target: SystemId,
184 at: InsertPos,
185 live: Tick,
186 ) -> WithResult<&mut Self, (), EcsError>;
187
188 fn inactivate_system(&mut self, sid: SystemId) -> WithResult<&mut Self, (), EcsError>;
211
212 fn register_entity_of<T>(&mut self) -> WithResult<&mut Self, EntityIndex, EcsError>
229 where
230 T: AsEntityReg,
231 {
232 self.register_entity(T::entity_descriptor())
233 }
234
235 fn register_entity(&mut self, desc: EntityReg) -> WithResult<&mut Self, EntityIndex, EcsError>;
255
256 fn unregister_entity<C>(&mut self) -> WithResult<&mut Self, Box<dyn ContainEntity>, EcsError>
284 where
285 C: Components;
286
287 fn add_entity<E>(
302 &mut self,
303 ei: EntityIndex,
304 value: E,
305 ) -> WithResult<&mut Self, EntityId, EcsError<E>>
306 where
307 E: Entity;
308
309 fn remove_entity(&mut self, eid: EntityId) -> WithResult<&mut Self, (), EcsError>;
326
327 fn add_resources<T>(&mut self, descs: T) -> WithResult<&mut Self, (), EcsError>
344 where
345 T: HelpAddManyResources,
346 {
347 descs.add_resources(self)
348 }
349
350 fn add_resource<T>(
380 &mut self,
381 desc: T,
382 ) -> WithResult<&mut Self, ResourceIndex, EcsError<ResourceDesc>>
383 where
384 T: Into<ResourceDesc>;
385
386 fn remove_resource<R>(&mut self) -> WithResult<&mut Self, Option<R>, EcsError>
405 where
406 R: Resource;
407
408 fn get_resource<R>(&self) -> Option<&R>
424 where
425 R: Resource;
426
427 fn get_resource_mut<R>(&mut self) -> Option<&mut R>
447 where
448 R: Resource;
449
450 fn get_resource_index<R>(&self) -> Option<ResourceIndex>
466 where
467 R: Resource;
468
469 fn execute_commands<T>(
486 &mut self,
487 cmds: T,
488 ) -> WithResult<&mut Self, (), Box<dyn Error + Send + Sync + 'static>>
489 where
490 T: HelpExecuteManyCommands;
491
492 fn execute_command<F, R>(
516 &mut self,
517 f: F,
518 ) -> WithResult<&mut Self, (), Box<dyn Error + Send + Sync + 'static>>
519 where
520 F: FnOnce(Commander) -> R,
521 R: Command;
522
523 fn errors(&mut self) -> Vec<Box<dyn Error + Send + Sync + 'static>>;
528}
529
530pub trait HelpAddManySystems<Systems> {
534 fn add_systems<Ecs>(self, ecs: &mut Ecs) -> WithResult<&mut Ecs, (), EcsError>
535 where
536 Ecs: EcsEntry + ?Sized;
537}
538
539macro_rules! impl_help_add_many_systems {
541 ($n:expr, $($i:expr),*) => {
542 paste::paste! {
543 #[allow(unused_parens, non_snake_case)]
544 impl<$([<A $i>], [<S $i>]),*> HelpAddManySystems<( $([<S $i>]),* )>
545 for ( $([<A $i>]),* )
546 where
547 $(
548 [<A $i>]: Into<SystemDesc<[<S $i>]>>,
549 [<S $i>]: System,
550 )*
551 {
552 fn add_systems<Ecs>(self, ecs: &mut Ecs) -> WithResult<&mut Ecs, (), EcsError>
553 where
554 Ecs: EcsEntry + ?Sized,
555 {
556 let ( $([<A $i>]),* ) = self;
557
558 $(
559 match ecs.add_system([<A $i>]).take() {
560 Ok(_) => {}
561 Err(e) => return WithResult::new(ecs, Err(e.without_data())),
562 }
563 )*
564
565 WithResult::new(ecs, Ok(()))
566 }
567 }
568 }
569 };
570}
571repeat_macro!(impl_help_add_many_systems, 1..=8);
572
573pub trait HelpAddManyOnce<Once> {
577 fn add_once_systems<Ecs>(self, ecs: &mut Ecs) -> WithResult<&mut Ecs, (), EcsError>
578 where
579 Ecs: EcsEntry + ?Sized;
580}
581
582macro_rules! impl_help_add_many_once {
584 ($n:expr, $($i:expr),*) => {
585 paste::paste! {
586 #[allow(unused_parens, non_snake_case)]
587 impl<$([<A $i>], [<R $i>], [<S $i>]),*> HelpAddManyOnce<( $( [<R $i>], [<S $i>] ),* )>
588 for ( $([<A $i>]),* )
589 where
590 $(
591 [<A $i>]: Into<FnOnceSystem<[<R $i>], [<S $i>]>>,
592 FnOnceSystem<[<R $i>], [<S $i>]>: System,
593 )*
594 {
595 fn add_once_systems<Ecs>(self, ecs: &mut Ecs) -> WithResult<&mut Ecs, (), EcsError>
596 where
597 Ecs: EcsEntry + ?Sized,
598 {
599 let ( $([<A $i>]),* ) = self;
600
601 $(
602 match ecs.add_once_system([<A $i>]).take() {
603 Ok(_) => {}
604 Err(e) => return WithResult::new(ecs, Err(e.without_data())),
605 }
606 )*
607
608 WithResult::new(ecs, Ok(()))
609 }
610 }
611 }
612 };
613}
614repeat_macro!(impl_help_add_many_once, 1..=8);
615
616pub trait HelpAddManyResources {
620 fn add_resources<Ecs>(self, ecs: &mut Ecs) -> WithResult<&mut Ecs, (), EcsError>
621 where
622 Ecs: EcsEntry + ?Sized;
623}
624
625macro_rules! impl_help_add_many_resources {
627 ($n:expr, $($i:expr),*) => {
628 paste::paste! {
629 #[allow(unused_parens, non_snake_case)]
630 impl<$([<A $i>]),*> HelpAddManyResources for ( $([<A $i>]),* )
631 where
632 $(
633 [<A $i>]: Into<ResourceDesc>,
634 )*
635 {
636 fn add_resources<Ecs>(
637 self,
638 ecs: &mut Ecs
639 ) -> WithResult<&mut Ecs, (), EcsError>
640 where
641 Ecs: EcsEntry + ?Sized,
642 {
643 let ( $([<A $i>]),* ) = self;
644
645 $(
646 match ecs.add_resource([<A $i>]).take() {
647 Ok(_) => {}
648 Err(e) => return WithResult::new(ecs, Err(e.without_data())),
649 }
650 )*
651
652 WithResult::new(ecs, Ok(()))
653 }
654 }
655 }
656 };
657}
658repeat_macro!(impl_help_add_many_resources, 1..=8);
659
660pub trait HelpExecuteManyCommands {
664 fn command(&mut self, ecs: Ecs<'_>) -> DynResult<()>;
665}
666
667macro_rules! impl_help_execute_many_commands {
669 (1, 0) => {
670 impl<A0: Command> HelpExecuteManyCommands for A0 {
671 fn command(&mut self, ecs: Ecs<'_>) -> DynResult<()> {
672 self.command(ecs)
673 }
674 }
675 };
676 ($n:expr, $($i:expr),*) => {
677 paste::paste! {
678 #[allow(unused_parens)]
679 impl<$([<A $i>]: Command),*> HelpExecuteManyCommands for ( $([<A $i>]),* ) {
680 fn command(&mut self, ecs: Ecs<'_>) -> DynResult<()> {
681 $(
682 match self.$i.command(unsafe { ecs.copy() }) {
683 Ok(()) => {}
684 Err(e) => return Err(e),
685 }
686 )*
687 Ok(())
688 }
689 }
690 }
691 };
692}
693repeat_macro!(impl_help_execute_many_commands, 1..=8);
694
695#[rustfmt::skip]
704#[allow(clippy::type_complexity)]
705#[derive(Debug)]
706struct EcsVTable {
707 register_system_inner:
710 unsafe fn(NonNull<u8>, SystemData, u16, bool, bool)
711 -> Result<SystemId, EcsError<SystemData>>,
712
713 unregister_system_inner:
714 unsafe fn(NonNull<u8>, &SystemId) -> Result<(), EcsError>,
715
716 activate_system_inner:
717 unsafe fn(NonNull<u8>, SystemId, InsertPos, Tick)
718 -> Result<(), EcsError>,
719
720 inactivate_system_inner:
721 unsafe fn(NonNull<u8>, &SystemId) -> Result<(), EcsError>,
722
723 register_entity_inner:
726 unsafe fn(NonNull<u8>, EntityReg) -> Result<EntityIndex, EcsError>,
727
728 unregister_entity_inner:
729 unsafe fn(NonNull<u8>, EntityKeyRef<'_>) -> Result<Box<dyn ContainEntity>, EcsError>,
730
731 get_entity_container_mut:
732 unsafe fn(NonNull<u8>, EntityKeyRef<'_>) -> Option<&mut EntityContainer>,
733
734 add_resource_inner:
737 unsafe fn(NonNull<u8>, ResourceDesc)
738 -> Result<ResourceIndex, EcsError<ResourceDesc>>,
739
740 remove_resource_inner:
741 unsafe fn(NonNull<u8>, &ResourceKey)
742 -> Result<Option<Box<dyn Any>>, EcsError>,
743
744 get_resource_inner:
745 unsafe fn(NonNull<u8>, &ResourceKey) -> Option<NonNull<u8>>,
746
747 get_resource_mut_inner:
748 unsafe fn(NonNull<u8>, &ResourceKey) -> Option<NonNull<u8>>,
749
750 get_resource_index_inner:
751 unsafe fn(NonNull<u8>, &ResourceKey) -> Option<ResourceIndex>,
752
753 post_ptr:
756 unsafe fn(NonNull<u8>) -> NonNull<Post>,
757
758 step:
759 unsafe fn(NonNull<u8>),
760
761 errors:
762 unsafe fn(NonNull<u8>) -> Vec<Box<dyn Error + Send + Sync + 'static>>,
763}
764
765impl EcsVTable {
766 fn new<W, S>() -> Self
767 where
768 W: Work + 'static,
769 S: BuildHasher + Default + 'static,
770 {
771 unsafe fn register_system_inner<W, S>(
772 this: NonNull<u8>,
773 sdata: SystemData,
774 group_index: u16,
775 volatile: bool,
776 private: bool,
777 ) -> Result<SystemId, EcsError<SystemData>>
778 where
779 W: Work + 'static,
780 S: BuildHasher + Default + 'static,
781 {
782 let this: &mut EcsApp<W, S> = unsafe { this.cast().as_mut() };
783 this.register_system_inner(sdata, group_index, volatile, private)
784 }
785
786 unsafe fn unregister_system_inner<W, S>(
787 this: NonNull<u8>,
788 sid: &SystemId,
789 ) -> Result<(), EcsError>
790 where
791 W: Work + 'static,
792 S: BuildHasher + Default + 'static,
793 {
794 let this: &mut EcsApp<W, S> = unsafe { this.cast().as_mut() };
795 this.unregister_system_inner(sid)
796 }
797
798 unsafe fn activate_system_inner<W, S>(
799 this: NonNull<u8>,
800 target: SystemId,
801 at: InsertPos,
802 live: Tick,
803 ) -> Result<(), EcsError>
804 where
805 W: Work + 'static,
806 S: BuildHasher + Default + 'static,
807 {
808 let this: &mut EcsApp<W, S> = unsafe { this.cast().as_mut() };
809 this.activate_system_inner(target, at, live)
810 }
811
812 unsafe fn inactivate_system_inner<W, S>(
813 this: NonNull<u8>,
814 sid: &SystemId,
815 ) -> Result<(), EcsError>
816 where
817 W: Work + 'static,
818 S: BuildHasher + Default + 'static,
819 {
820 let this: &mut EcsApp<W, S> = unsafe { this.cast().as_mut() };
821 this.inactivate_system_inner(sid)
822 }
823
824 unsafe fn register_entity_inner<W, S>(
825 this: NonNull<u8>,
826 desc: EntityReg,
827 ) -> Result<EntityIndex, EcsError>
828 where
829 W: Work + 'static,
830 S: BuildHasher + Default + 'static,
831 {
832 let this: &mut EcsApp<W, S> = unsafe { this.cast().as_mut() };
833 this.register_entity_inner(desc)
834 }
835
836 unsafe fn unregister_entity_inner<W, S>(
837 this: NonNull<u8>,
838 ekey: EntityKeyRef<'_>,
839 ) -> Result<Box<dyn ContainEntity>, EcsError>
840 where
841 W: Work + 'static,
842 S: BuildHasher + Default + 'static,
843 {
844 let this: &mut EcsApp<W, S> = unsafe { this.cast().as_mut() };
845 this.unregister_entity_inner(ekey)
846 }
847
848 unsafe fn get_entity_container_mut<'o, W, S>(
849 this: NonNull<u8>,
850 ekey: EntityKeyRef<'_>,
851 ) -> Option<&'o mut EntityContainer>
852 where
853 W: Work + 'static,
854 S: BuildHasher + Default + 'static,
855 {
856 let this: &'o mut EcsApp<W, S> = unsafe { this.cast().as_mut() };
857 this.get_entity_container_mut(ekey)
858 }
859
860 unsafe fn add_resource_inner<W, S>(
861 this: NonNull<u8>,
862 desc: ResourceDesc,
863 ) -> Result<ResourceIndex, EcsError<ResourceDesc>>
864 where
865 W: Work + 'static,
866 S: BuildHasher + Default + 'static,
867 {
868 let this: &mut EcsApp<W, S> = unsafe { this.cast().as_mut() };
869 this.add_resource_inner(desc)
870 }
871
872 unsafe fn remove_resource_inner<W, S>(
873 this: NonNull<u8>,
874 rkey: &ResourceKey,
875 ) -> Result<Option<Box<dyn Any>>, EcsError>
876 where
877 W: Work + 'static,
878 S: BuildHasher + Default + 'static,
879 {
880 let this: &mut EcsApp<W, S> = unsafe { this.cast().as_mut() };
881 this.remove_resource_inner(rkey)
882 }
883
884 unsafe fn get_resource_inner<W, S>(
885 this: NonNull<u8>,
886 rkey: &ResourceKey,
887 ) -> Option<NonNull<u8>>
888 where
889 W: Work + 'static,
890 S: BuildHasher + Default + 'static,
891 {
892 let this: &mut EcsApp<W, S> = unsafe { this.cast().as_mut() };
893 this.get_resource_inner(rkey)
894 }
895
896 unsafe fn get_resource_mut_inner<W, S>(
897 this: NonNull<u8>,
898 rkey: &ResourceKey,
899 ) -> Option<NonNull<u8>>
900 where
901 W: Work + 'static,
902 S: BuildHasher + Default + 'static,
903 {
904 let this: &mut EcsApp<W, S> = unsafe { this.cast().as_mut() };
905 this.get_resource_mut_inner(rkey)
906 }
907
908 unsafe fn get_resource_index_inner<W, S>(
909 this: NonNull<u8>,
910 rkey: &ResourceKey,
911 ) -> Option<ResourceIndex>
912 where
913 W: Work + 'static,
914 S: BuildHasher + Default + 'static,
915 {
916 let this: &mut EcsApp<W, S> = unsafe { this.cast().as_mut() };
917 this.get_resource_index_inner(rkey)
918 }
919
920 unsafe fn post_ptr<W, S>(this: NonNull<u8>) -> NonNull<Post>
921 where
922 W: Work + 'static,
923 S: BuildHasher + Default + 'static,
924 {
925 let this: &mut EcsApp<W, S> = unsafe { this.cast().as_mut() };
926 let post = this.get_resource::<Post>().unwrap();
927 unsafe { NonNull::new_unchecked((post as *const Post).cast_mut()) }
928 }
929
930 unsafe fn step<W, S>(this: NonNull<u8>)
931 where
932 W: Work + 'static,
933 S: BuildHasher + Default + 'static,
934 {
935 let this: &mut EcsApp<W, S> = unsafe { this.cast().as_mut() };
936 this.step();
937 }
938
939 unsafe fn errors<W, S>(this: NonNull<u8>) -> Vec<Box<dyn Error + Send + Sync + 'static>>
940 where
941 W: Work + 'static,
942 S: BuildHasher + Default + 'static,
943 {
944 let this: &mut EcsApp<W, S> = unsafe { this.cast().as_mut() };
945 this.errors()
946 }
947
948 Self {
949 register_system_inner: register_system_inner::<W, S>,
950 unregister_system_inner: unregister_system_inner::<W, S>,
951 activate_system_inner: activate_system_inner::<W, S>,
952 inactivate_system_inner: inactivate_system_inner::<W, S>,
953 register_entity_inner: register_entity_inner::<W, S>,
954 unregister_entity_inner: unregister_entity_inner::<W, S>,
955 get_entity_container_mut: get_entity_container_mut::<W, S>,
956 add_resource_inner: add_resource_inner::<W, S>,
957 remove_resource_inner: remove_resource_inner::<W, S>,
958 get_resource_inner: get_resource_inner::<W, S>,
959 get_resource_mut_inner: get_resource_mut_inner::<W, S>,
960 get_resource_index_inner: get_resource_index_inner::<W, S>,
961 post_ptr: post_ptr::<W, S>,
962 step: step::<W, S>,
963 errors: errors::<W, S>,
964 }
965 }
966}
967
968#[derive(Debug)]
976pub struct Ecs<'ecs> {
977 this: NonNull<u8>,
979
980 vtable: NonNull<EcsVTable>,
982
983 _marker: PhantomData<&'ecs mut ()>,
985}
986
987impl<'ecs> Ecs<'ecs> {
988 pub fn default<Wp, W, G>(pool: Wp, groups: G) -> EcsApp<W, RandomState>
1008 where
1009 Wp: Into<Vec<W>>,
1010 W: Work + 'static,
1011 G: AsRef<[usize]>,
1012 {
1013 Self::create(pool.into(), groups.as_ref())
1014 }
1015
1016 pub fn create<Wp, W, G, S>(pool: Wp, groups: G) -> EcsApp<W, S>
1043 where
1044 Wp: Into<Vec<W>>,
1045 W: Work + 'static,
1046 G: AsRef<[usize]>,
1047 S: BuildHasher + Default + 'static,
1048 {
1049 EcsApp::new(pool.into(), groups.as_ref())
1050 }
1051
1052 fn new<W, S>(ecs: &'ecs mut EcsApp<W, S>) -> Self
1053 where
1054 W: Work + 'static,
1055 S: BuildHasher + Default + 'static,
1056 {
1057 unsafe {
1058 let this = NonNull::new_unchecked(ecs as *mut _ as *mut u8);
1059 let vtable = NonNull::new_unchecked(&mut ecs.vtable as *mut _);
1060 Self {
1061 this,
1062 vtable,
1063 _marker: PhantomData,
1064 }
1065 }
1066 }
1067
1068 pub(crate) unsafe fn copy(&self) -> Self {
1074 Self {
1075 this: self.this,
1076 vtable: self.vtable,
1077 _marker: self._marker,
1078 }
1079 }
1080
1081 pub(crate) fn entity_container_ptr(
1087 &self,
1088 ekey: EntityKeyRef<'_>,
1089 ) -> Option<NonNull<EntityContainer>> {
1090 unsafe {
1091 let vtable = self.vtable.as_ref();
1092 (vtable.get_entity_container_mut)(self.this, ekey)
1093 .map(|cont| NonNull::new_unchecked(cont as *mut _))
1094 }
1095 }
1096
1097 pub(crate) fn post_ptr(&self) -> NonNull<Post> {
1098 unsafe {
1099 let vtable = self.vtable.as_ref();
1100 (vtable.post_ptr)(self.this)
1101 }
1102 }
1103}
1104
1105impl EcsEntry for Ecs<'_> {
1106 fn add_system<T, Sys>(
1107 &mut self,
1108 desc: T,
1109 ) -> WithResult<&mut Self, SystemId, EcsError<SystemDesc<Sys>>>
1110 where
1111 T: Into<SystemDesc<Sys>>,
1112 Sys: System,
1113 {
1114 let desc = desc.into();
1115 let SystemDesc {
1116 sys,
1117 private,
1118 group_index,
1119 volatile,
1120 activation: (live, insert_at),
1121 } = desc;
1122 let sdata = match sys {
1123 Or::A(sys) => sys.into_data(),
1124 Or::B(sdata) => sdata,
1125 };
1126
1127 let res = unsafe {
1129 let vtable = self.vtable.as_ref();
1130 (vtable.register_system_inner)(self.this, sdata, group_index, volatile, private)
1131 };
1132
1133 if let Ok(sid) = res.as_ref() {
1137 if live > 0 {
1138 let must_ok = self.activate_system(*sid, insert_at, live);
1139 assert!(must_ok.is_ok());
1140 }
1141 }
1142
1143 let res = res.map_err(|err| {
1144 err.map_data(|sdata| {
1145 let sys = match sdata.try_into_any() {
1146 Ok(any) => {
1147 let sys = *any.downcast::<Sys>().unwrap();
1148 Or::A(sys)
1149 }
1150 Err(sdata) => Or::B(sdata),
1151 };
1152 SystemDesc {
1153 sys,
1154 private,
1155 group_index,
1156 volatile,
1157 activation: (live, insert_at),
1158 }
1159 })
1160 });
1161 WithResult::new(self, res)
1162 }
1163
1164 fn add_once_system<T, Req, F>(
1165 &mut self,
1166 sys: T,
1167 ) -> WithResult<&mut Self, SystemId, EcsError<SystemDesc<FnOnceSystem<Req, F>>>>
1168 where
1169 T: Into<FnOnceSystem<Req, F>>,
1170 FnOnceSystem<Req, F>: System,
1171 {
1172 let desc = SystemDesc::new().with_once(sys);
1173 self.add_system(desc)
1174 }
1175
1176 fn unregister_system(&mut self, sid: SystemId) -> WithResult<&mut Self, (), EcsError> {
1177 let res = unsafe {
1178 let vtable = self.vtable.as_ref();
1179 (vtable.unregister_system_inner)(self.this, &sid)
1180 };
1181 WithResult::new(self, res)
1182 }
1183
1184 fn activate_system(
1185 &mut self,
1186 target: SystemId,
1187 at: InsertPos,
1188 live: Tick,
1189 ) -> WithResult<&mut Self, (), EcsError> {
1190 let res = unsafe {
1191 let vtable = self.vtable.as_ref();
1192 (vtable.activate_system_inner)(self.this, target, at, live)
1193 };
1194 WithResult::new(self, res)
1195 }
1196
1197 fn inactivate_system(&mut self, sid: SystemId) -> WithResult<&mut Self, (), EcsError> {
1198 let res = unsafe {
1199 let vtable = self.vtable.as_ref();
1200 (vtable.inactivate_system_inner)(self.this, &sid)
1201 };
1202 WithResult::new(self, res)
1203 }
1204
1205 fn register_entity(&mut self, desc: EntityReg) -> WithResult<&mut Self, EntityIndex, EcsError> {
1206 let res = unsafe {
1207 let vtable = self.vtable.as_ref();
1208 (vtable.register_entity_inner)(self.this, desc)
1209 };
1210 WithResult::new(self, res)
1211 }
1212
1213 fn unregister_entity<C>(&mut self) -> WithResult<&mut Self, Box<dyn ContainEntity>, EcsError>
1214 where
1215 C: Components,
1216 {
1217 let ckeys = C::sorted_keys();
1218 let ekey = EntityKeyRef::Ckeys(ckeys.as_ref());
1219 let res = unsafe {
1220 let vtable = self.vtable.as_ref();
1221 (vtable.unregister_entity_inner)(self.this, ekey)
1222 };
1223 WithResult::new(self, res)
1224 }
1225
1226 fn add_entity<E>(
1227 &mut self,
1228 ei: EntityIndex,
1229 value: E,
1230 ) -> WithResult<&mut Self, EntityId, EcsError<E>>
1231 where
1232 E: Entity,
1233 {
1234 let ekey = EntityKeyRef::Index(&ei);
1235
1236 let cont = unsafe {
1237 let vtable = self.vtable.as_ref();
1238 (vtable.get_entity_container_mut)(self.this, ekey)
1239 };
1240
1241 let res = if let Some(cont) = cont {
1242 let ri = value.move_to(&mut **cont);
1243 Ok(EntityId::new(ei, ri))
1244 } else {
1245 let reason = debug_format!("failed to find `{}`", std::any::type_name::<E>());
1246 Err(EcsError::UnknownEntity(reason, value))
1247 };
1248 WithResult::new(self, res)
1249 }
1250
1251 fn remove_entity(&mut self, eid: EntityId) -> WithResult<&mut Self, (), EcsError> {
1252 let ei = eid.container_index();
1253 let ekey = EntityKeyRef::Index(&ei);
1254
1255 let cont = unsafe {
1256 let vtable = self.vtable.as_ref();
1257 (vtable.get_entity_container_mut)(self.this, ekey)
1258 };
1259
1260 let res = if let Some(cont) = cont {
1261 let ri = eid.row_index();
1262 let is_removed = cont.remove_row(ri);
1263 if is_removed {
1264 Ok(())
1265 } else {
1266 let reason = debug_format!("failed to find an entity for {eid:?}");
1267 Err(EcsError::UnknownEntity(reason, ()))
1268 }
1269 } else {
1270 let reason = debug_format!("failed to find an entity for {eid:?}");
1271 Err(EcsError::UnknownEntity(reason, ()))
1272 };
1273 WithResult::new(self, res)
1274 }
1275
1276 fn add_resource<T>(
1277 &mut self,
1278 desc: T,
1279 ) -> WithResult<&mut Self, ResourceIndex, EcsError<ResourceDesc>>
1280 where
1281 T: Into<ResourceDesc>,
1282 {
1283 let res = unsafe {
1284 let vtable = self.vtable.as_ref();
1285 (vtable.add_resource_inner)(self.this, desc.into())
1286 };
1287 WithResult::new(self, res)
1288 }
1289
1290 fn remove_resource<R>(&mut self) -> WithResult<&mut Self, Option<R>, EcsError>
1291 where
1292 R: Resource,
1293 {
1294 let res = unsafe {
1295 let vtable = self.vtable.as_ref();
1296 (vtable.remove_resource_inner)(self.this, &R::key())
1297 };
1298 let res = res.map(|opt| opt.map(|any| *any.downcast::<R>().unwrap()));
1299 WithResult::new(self, res)
1300 }
1301
1302 fn get_resource<R>(&self) -> Option<&R>
1303 where
1304 R: Resource,
1305 {
1306 unsafe {
1307 let vtable = self.vtable.as_ref();
1308 (vtable.get_resource_inner)(self.this, &R::key()).map(|ptr| ptr.cast::<R>().as_ref())
1309 }
1310 }
1311
1312 fn get_resource_mut<R>(&mut self) -> Option<&mut R>
1313 where
1314 R: Resource,
1315 {
1316 unsafe {
1317 let vtable = self.vtable.as_ref();
1318 (vtable.get_resource_mut_inner)(self.this, &R::key())
1319 .map(|ptr| ptr.cast::<R>().as_mut())
1320 }
1321 }
1322
1323 fn get_resource_index<R>(&self) -> Option<ResourceIndex>
1324 where
1325 R: Resource,
1326 {
1327 unsafe {
1328 let vtable = self.vtable.as_ref();
1329 (vtable.get_resource_index_inner)(self.this, &R::key())
1330 }
1331 }
1332
1333 fn execute_commands<T>(
1334 &mut self,
1335 mut cmds: T,
1336 ) -> WithResult<&mut Self, (), Box<dyn Error + Send + Sync + 'static>>
1337 where
1338 T: HelpExecuteManyCommands,
1339 {
1340 let res = cmds.command(unsafe { self.copy() });
1341 WithResult::new(self, res)
1342 }
1343
1344 fn execute_command<F, R>(
1345 &mut self,
1346 f: F,
1347 ) -> WithResult<&mut Self, (), Box<dyn Error + Send + Sync + 'static>>
1348 where
1349 F: FnOnce(Commander) -> R,
1350 R: Command,
1351 {
1352 let post = self.get_resource::<Post>().unwrap();
1353 let cmdr = post.as_commander();
1354 let mut cmd = f(cmdr);
1355 let res = cmd.command(unsafe { self.copy() });
1356 WithResult::new(self, res)
1357 }
1358
1359 fn errors(&mut self) -> Vec<Box<dyn Error + Send + Sync + 'static>> {
1360 unsafe {
1361 let vtable = self.vtable.as_ref();
1362 (vtable.errors)(self.this)
1363 }
1364 }
1365}
1366
1367#[derive(Debug)]
1377pub struct EcsApp<W, S = RandomState>
1378where
1379 W: Work + 'static,
1380 S: BuildHasher + Default + 'static,
1381{
1382 sys_stor: SystemStorage<S>,
1384
1385 ent_stor: EntityStorage<S>,
1388
1389 res_stor: ResourceStorage<S>,
1392
1393 cache_stor: CacheStorage<S>,
1394
1395 sched: Scheduler<W, S>,
1396
1397 cmd_errs: Vec<Box<dyn Error + Send + Sync + 'static>>,
1398
1399 vtable: EcsVTable,
1400
1401 tx_cmd: CommandSender,
1402 rx_cmd: Rc<CommandReceiver>,
1403}
1404
1405impl<W, S> EcsApp<W, S>
1406where
1407 W: Work + 'static,
1408 S: BuildHasher + Default + 'static,
1409{
1410 pub fn new(workers: Vec<W>, groups: &[usize]) -> Self {
1438 let groups = if groups.is_empty() { &[0][..] } else { groups };
1440
1441 let (tx_cmd, rx_cmd) = command_channel(thread::current());
1442 let rx_cmd = Rc::new(rx_cmd);
1443 let sched = Scheduler::new(workers, groups, tx_cmd.clone(), Rc::clone(&rx_cmd));
1444
1445 let mut this = Self {
1446 sys_stor: SystemStorage::new(groups.len()),
1447 ent_stor: EntityStorage::new(),
1448 res_stor: ResourceStorage::new(),
1449 cache_stor: CacheStorage::new(),
1450 sched,
1451 cmd_errs: Vec::new(),
1452 vtable: EcsVTable::new::<W, S>(),
1453 tx_cmd: tx_cmd.clone(),
1454 rx_cmd,
1455 };
1456
1457 let tx_msg = this.sched.get_send_message_queue().clone();
1459 let fut_cnt = Arc::clone(this.sched.get_future_count());
1460 let tx_dedi = this.sched.get_tx_dedi_queue().clone();
1461 let post = Post::new(tx_cmd, tx_msg, tx_dedi, fut_cnt);
1462 this.add_resource(post).unwrap();
1463
1464 this
1465 }
1466
1467 pub fn destroy(mut self) -> Vec<W> {
1469 self.clear_command();
1471 self.clear_system();
1472
1473 let tx_cmd = self.tx_cmd.clone();
1475 let rx_cmd = Rc::clone(&self.rx_cmd);
1476 let old = mem::replace(
1477 &mut self.sched,
1478 Scheduler::new(Vec::new(), &[], tx_cmd, rx_cmd),
1479 );
1480 old.take_workers()
1481 }
1482
1483 pub fn collect_poisoned_systems(&mut self) -> Vec<PoisonedSystem> {
1499 self.sys_stor.drain_poisoned().collect()
1500 }
1501
1502 pub fn shrink_to_fit(&mut self) {
1504 let post = self.get_resource::<Post>().unwrap();
1505 post.shrink_to_fit();
1506 }
1508
1509 pub fn step(&mut self) -> &mut Self {
1531 self._step();
1532 self
1533 }
1534
1535 fn _step(&mut self) -> bool {
1537 let sgroups = &mut self.sys_stor.sgroups;
1539 let mut cache =
1540 RefreshCacheStorage::new(&mut self.cache_stor, &mut self.ent_stor, &mut self.res_stor);
1541 self.sched.execute_all(sgroups, &mut cache);
1542
1543 let run_cmd = self.process_buffered_commands();
1545
1546 self.clear_dead_system();
1548
1549 run_cmd
1550 }
1551
1552 pub fn run<F, R>(&mut self, mut handle_error: F) -> With<&mut Self, Vec<R>>
1575 where
1576 F: FnMut(Box<dyn Error + Send + Sync + 'static>) -> R,
1577 {
1578 debug_assert_eq!(self.sched.num_groups(), self.sys_stor.num_groups());
1579
1580 let mut ret = Vec::new();
1581
1582 loop {
1583 let run_cmd = self._step();
1584 let is_completed = self.wait_for_idle().is_completed();
1585
1586 for err in self.errors() {
1587 ret.push(handle_error(err));
1588 }
1589
1590 if is_completed {
1591 break;
1592 }
1593
1594 if !run_cmd && self.sched.has_dedicated_future() {
1599 self.sched.wait_receiving_dedicated_task();
1600 }
1601 }
1602
1603 With::new(self, ret)
1604 }
1605
1606 pub fn wait_for_idle(&mut self) -> &mut Self {
1610 self.sched.wait_exhausted();
1611 self
1612 }
1613
1614 pub fn is_completed(&self) -> bool {
1622 let no_active = self
1624 .sys_stor
1625 .sgroups
1626 .iter()
1627 .all(|sgroup| sgroup.len_active() == 0);
1628
1629 let no_cmd = !self.sched.has_command();
1631
1632 let no_fut = !self.sched.has_dedicated_future();
1634
1635 let is_sub_exhausted = self.sched.is_work_groups_exhausted();
1637
1638 is_sub_exhausted && no_active && no_cmd && no_fut
1639 }
1640
1641 fn register_system_inner(
1644 &mut self,
1645 mut sdata: SystemData,
1646 group_index: u16,
1647 volatile: bool,
1648 private: bool,
1649 ) -> Result<SystemId, EcsError<SystemData>> {
1650 if let Err(e) = validate_request::<W, S>(self, &sdata) {
1651 return Err(e.with_data(sdata));
1652 }
1653 complete_data::<W, S>(self, &mut sdata, group_index, private);
1654 let sid = sdata.id();
1655 return self.sys_stor.register(sdata, volatile).map(|()| sid);
1656
1657 fn validate_request<W, S>(this: &EcsApp<W, S>, sdata: &SystemData) -> Result<(), EcsError>
1660 where
1661 W: Work + 'static,
1662 S: BuildHasher + Default + 'static,
1663 {
1664 let rinfo = sdata.get_request_info();
1677 if let Err(reason) = rinfo.validate() {
1678 return Err(EcsError::InvalidRequest(reason, ()));
1679 }
1680
1681 for rkey in rinfo.resource_keys() {
1683 if !this.res_stor.contains(rkey) {
1684 let reason = debug_format!("failed to find a resource `{:?}`", rkey);
1685 return Err(EcsError::UnknownResource(reason, ()));
1686 }
1687 }
1688
1689 let r_sinfos = rinfo.read().1.select_infos();
1691 let w_sinfos = rinfo.write().1.select_infos();
1692 for (sinfo, finfo) in r_sinfos
1693 .chain(w_sinfos)
1694 .flat_map(|sinfo| rinfo.filters().iter().map(move |(_, finfo)| (sinfo, finfo)))
1695 {
1696 if !sinfo.is_disjoint2(finfo) {
1697 let reason = debug_format!(
1698 "{} contains conflicting queries: {}, {}",
1699 rinfo.name(),
1700 sinfo.name(),
1701 finfo.name(),
1702 );
1703 return Err(EcsError::InvalidRequest(reason, ()));
1704 }
1705 }
1706
1707 Ok(())
1708 }
1709
1710 fn complete_data<W, S>(
1711 this: &mut EcsApp<W, S>,
1712 sdata: &mut SystemData,
1713 group_index: u16,
1714 private: bool,
1715 ) where
1716 W: Work + 'static,
1717 S: BuildHasher + Default + 'static,
1718 {
1719 debug_assert!(sdata.id().is_dummy());
1721 {
1722 let sid = this
1723 .sys_stor
1724 .get_group_mut(group_index as usize)
1725 .next_system_id();
1726 sdata.set_id(sid);
1727 }
1728
1729 debug_assert!(sdata.flags().is_dedi_empty() && sdata.flags().is_private_empty());
1731 {
1732 let mut sflags = SystemFlags::empty();
1733
1734 let res_read = &sdata.get_request_info().res_read().1;
1736 let res_write = &sdata.get_request_info().res_write().1;
1737 if res_read
1738 .resource_keys()
1739 .iter()
1740 .chain(res_write.resource_keys())
1741 .any(|rkey| this.res_stor.is_dedicated2(rkey).unwrap())
1742 {
1743 sflags |= SystemFlags::DEDI_SET;
1744 } else {
1745 sflags |= SystemFlags::DEDI_RESET;
1746 }
1747
1748 if private {
1750 sflags |= SystemFlags::PRIVATE_SET;
1751 } else {
1752 sflags |= SystemFlags::PRIVATE_RESET;
1753 }
1754
1755 debug_assert_eq!(this.sched.num_groups(), this.sys_stor.num_groups());
1757 if this.sched.num_workers() == 0 {
1758 sflags |= SystemFlags::DEDI_SET;
1759 }
1760
1761 sdata.union_flags(sflags);
1762 }
1763 }
1764 }
1765
1766 fn unregister_system_inner(&mut self, sid: &SystemId) -> Result<(), EcsError> {
1767 self.sys_stor.unregister(sid)
1768 }
1769
1770 fn activate_system_inner(
1771 &mut self,
1772 target: SystemId,
1773 at: InsertPos,
1774 live: Tick,
1775 ) -> Result<(), EcsError> {
1776 self.sys_stor.activate(&target, at, live)?;
1778
1779 let sgroup = self.sys_stor.get_group_mut(target.group_index() as usize);
1781 let sdata = unsafe { sgroup.get_active(&target).unwrap_unchecked() };
1784 self.cache_stor.remove_item(target);
1785 self.cache_stor
1786 .create_item(sdata, &mut self.ent_stor, &mut self.res_stor);
1787 Ok(())
1788 }
1789
1790 fn inactivate_system_inner(&mut self, sid: &SystemId) -> Result<(), EcsError> {
1791 self.sys_stor.inactivate(sid)
1792 }
1793
1794 fn register_entity_inner(&mut self, desc: EntityReg) -> Result<EntityIndex, EcsError> {
1795 let ei = self.ent_stor.register(desc)?;
1797 let ekey = EntityKeyRef::Index(&ei);
1798 self.cache_stor
1799 .update_by_entity_reg(ekey, &mut self.ent_stor, &mut self.res_stor);
1800
1801 let cont = unsafe { self.ent_stor.get_entity_container(ekey).unwrap_unchecked() };
1803 self.sched
1804 .get_wait_queues_mut()
1805 .initialize_entity_queue(ei.index(), cont.num_columns());
1806
1807 Ok(ei)
1808 }
1809
1810 fn unregister_entity_inner(
1811 &mut self,
1812 ekey: EntityKeyRef<'_>,
1813 ) -> Result<Box<dyn ContainEntity>, EcsError> {
1814 if self.ent_stor.get_entity_container(ekey).is_none() {
1815 let reason = debug_format!("failed to find an entity `{:?}`", ekey);
1816 return Err(EcsError::UnknownEntity(reason, ()));
1817 }
1818
1819 self.cache_stor
1821 .update_by_entity_unreg(ekey, &mut self.ent_stor, &mut self.res_stor);
1822
1823 let (_, cont) = self.ent_stor.unregister(ekey).unwrap();
1824 Ok(cont.into_inner())
1825 }
1826
1827 fn add_resource_inner(
1828 &mut self,
1829 desc: ResourceDesc,
1830 ) -> Result<ResourceIndex, EcsError<ResourceDesc>> {
1831 let ri = self.res_stor.add(desc)?;
1832 self.sched
1833 .get_wait_queues_mut()
1834 .initialize_resource_queue(ri.index());
1835 Ok(ri)
1836 }
1837
1838 fn remove_resource_inner(
1839 &mut self,
1840 rkey: &ResourceKey,
1841 ) -> Result<Option<Box<dyn Any>>, EcsError> {
1842 self.cache_stor
1843 .update_by_resource_unreg(rkey, |sid: &SystemId| {
1844 self.sys_stor.inactivate(sid).unwrap()
1845 });
1846 match self.res_stor.remove(rkey) {
1847 Some(Or::A(owned)) => Ok(Some(owned)),
1848 Some(Or::B(_ptr)) => Ok(None),
1849 None => {
1850 let reason = debug_format!("failed to find a resource `{:?}`", rkey);
1851 Err(EcsError::UnknownResource(reason, ()))
1852 }
1853 }
1854 }
1855
1856 fn get_resource_inner(&self, rkey: &ResourceKey) -> Option<NonNull<u8>> {
1857 match self.res_stor.borrow2(rkey) {
1858 Ok(borrowed) => Some(borrowed.as_nonnull()),
1861 Err(..) => None,
1862 }
1863 }
1864
1865 fn get_resource_mut_inner(&mut self, rkey: &ResourceKey) -> Option<NonNull<u8>> {
1866 match self.res_stor.borrow_mut2(rkey) {
1867 Ok(borrowed) => Some(borrowed.as_nonnull()),
1870 Err(..) => None,
1871 }
1872 }
1873
1874 fn get_resource_index_inner(&self, rkey: &ResourceKey) -> Option<ResourceIndex> {
1875 self.res_stor.index(rkey)
1876 }
1877
1878 fn process_buffered_commands(&mut self) -> bool {
1879 let mut run_cmd = false;
1880
1881 while let Ok(cmd) = self.rx_cmd.try_recv() {
1882 let ecs = Ecs::new(self);
1883 match cmd.command(ecs) {
1884 Ok(()) => {}
1885 Err(err) => self.cmd_errs.push(err),
1886 }
1887
1888 run_cmd = true;
1889 }
1890
1891 run_cmd
1892 }
1893
1894 fn clear_command(&mut self) {
1901 self.rx_cmd.close();
1903
1904 while let Ok(cmd) = self.rx_cmd.try_recv() {
1906 cmd.cancel();
1907 }
1908 }
1909
1910 fn clear_system(&mut self) {
1917 let num_groups = self.sys_stor.num_groups();
1918 for gi in 0..num_groups {
1919 self.sys_stor.get_group_mut(gi).clear();
1920 }
1921 }
1922
1923 fn clear_dead_system(&mut self) {
1925 for sdata in self.sys_stor.drain_dead() {
1926 self.cache_stor.remove_item(sdata.id());
1927 }
1928 }
1929
1930 fn get_entity_container_mut<'r, K>(&mut self, ekey: K) -> Option<&mut EntityContainer>
1931 where
1932 K: Into<EntityKeyRef<'r>>,
1933 {
1934 self.ent_stor.get_entity_container_mut(ekey)
1935 }
1936}
1937
1938impl<W, S> EcsEntry for EcsApp<W, S>
1939where
1940 W: Work + 'static,
1941 S: BuildHasher + Default + 'static,
1942{
1943 fn add_system<T, Sys>(
1944 &mut self,
1945 desc: T,
1946 ) -> WithResult<&mut Self, SystemId, EcsError<SystemDesc<Sys>>>
1947 where
1948 T: Into<SystemDesc<Sys>>,
1949 Sys: System,
1950 {
1951 let res = Ecs::new(self).add_system(desc).take();
1952 WithResult::new(self, res)
1953 }
1954
1955 fn add_once_system<T, Req, F>(
1956 &mut self,
1957 sys: T,
1958 ) -> WithResult<&mut Self, SystemId, EcsError<SystemDesc<FnOnceSystem<Req, F>>>>
1959 where
1960 T: Into<FnOnceSystem<Req, F>>,
1961 FnOnceSystem<Req, F>: System,
1962 {
1963 let res = Ecs::new(self).add_once_system(sys).take();
1964 WithResult::new(self, res)
1965 }
1966
1967 fn unregister_system(&mut self, sid: SystemId) -> WithResult<&mut Self, (), EcsError> {
1968 let res = Ecs::new(self).unregister_system(sid).take();
1969 WithResult::new(self, res)
1970 }
1971
1972 fn activate_system(
1973 &mut self,
1974 target: SystemId,
1975 at: InsertPos,
1976 live: Tick,
1977 ) -> WithResult<&mut Self, (), EcsError> {
1978 let res = Ecs::new(self).activate_system(target, at, live).take();
1979 WithResult::new(self, res)
1980 }
1981
1982 fn inactivate_system(&mut self, sid: SystemId) -> WithResult<&mut Self, (), EcsError> {
1983 let res = Ecs::new(self).inactivate_system(sid).take();
1984 WithResult::new(self, res)
1985 }
1986
1987 fn register_entity(&mut self, desc: EntityReg) -> WithResult<&mut Self, EntityIndex, EcsError> {
1988 let res = Ecs::new(self).register_entity(desc).take();
1989 WithResult::new(self, res)
1990 }
1991
1992 fn unregister_entity<C>(&mut self) -> WithResult<&mut Self, Box<dyn ContainEntity>, EcsError>
1993 where
1994 C: Components,
1995 {
1996 let res = Ecs::new(self).unregister_entity::<C>().take();
1997 WithResult::new(self, res)
1998 }
1999
2000 fn add_entity<E>(
2001 &mut self,
2002 ei: EntityIndex,
2003 value: E,
2004 ) -> WithResult<&mut Self, EntityId, EcsError<E>>
2005 where
2006 E: Entity,
2007 {
2008 let res = Ecs::new(self).add_entity(ei, value).take();
2009 WithResult::new(self, res)
2010 }
2011
2012 fn remove_entity(&mut self, eid: EntityId) -> WithResult<&mut Self, (), EcsError> {
2013 let res = Ecs::new(self).remove_entity(eid).take();
2014 WithResult::new(self, res)
2015 }
2016
2017 fn add_resource<T>(
2018 &mut self,
2019 desc: T,
2020 ) -> WithResult<&mut Self, ResourceIndex, EcsError<ResourceDesc>>
2021 where
2022 T: Into<ResourceDesc>,
2023 {
2024 let res = Ecs::new(self).add_resource(desc).take();
2025 WithResult::new(self, res)
2026 }
2027
2028 fn remove_resource<R>(&mut self) -> WithResult<&mut Self, Option<R>, EcsError>
2029 where
2030 R: Resource,
2031 {
2032 let res = Ecs::new(self).remove_resource::<R>().take();
2033 WithResult::new(self, res)
2034 }
2035
2036 fn get_resource<R>(&self) -> Option<&R>
2037 where
2038 R: Resource,
2039 {
2040 self.get_resource_inner(&R::key())
2041 .map(|ptr| unsafe { ptr.cast::<R>().as_ref() })
2042 }
2043
2044 fn get_resource_mut<R>(&mut self) -> Option<&mut R>
2045 where
2046 R: Resource,
2047 {
2048 self.get_resource_mut_inner(&R::key())
2049 .map(|ptr| unsafe { ptr.cast::<R>().as_mut() })
2050 }
2051
2052 fn get_resource_index<R>(&self) -> Option<ResourceIndex>
2053 where
2054 R: Resource,
2055 {
2056 self.get_resource_index_inner(&R::key())
2057 }
2058
2059 fn execute_commands<T>(
2060 &mut self,
2061 cmds: T,
2062 ) -> WithResult<&mut Self, (), Box<dyn Error + Send + Sync + 'static>>
2063 where
2064 T: HelpExecuteManyCommands,
2065 {
2066 let res = Ecs::new(self).execute_commands(cmds).take();
2067 WithResult::new(self, res)
2068 }
2069
2070 fn execute_command<F, R>(
2071 &mut self,
2072 f: F,
2073 ) -> WithResult<&mut Self, (), Box<dyn Error + Send + Sync + 'static>>
2074 where
2075 F: FnOnce(Commander) -> R,
2076 R: Command,
2077 {
2078 let res = Ecs::new(self).execute_command(f).take();
2079 WithResult::new(self, res)
2080 }
2081
2082 fn errors(&mut self) -> Vec<Box<dyn Error + Send + Sync + 'static>> {
2083 mem::take(&mut self.cmd_errs)
2084 }
2085}
2086
2087impl<W, S> Drop for EcsApp<W, S>
2088where
2089 W: Work + 'static,
2090 S: BuildHasher + Default + 'static,
2091{
2092 fn drop(&mut self) {
2093 self.clear_command();
2094 self.clear_system();
2095 }
2096}
2097
2098impl<W, S> Resource for EcsApp<W, S>
2099where
2100 EcsApp<W, S>: Send + 'static,
2101 W: Work + 'static,
2102 S: BuildHasher + Default + 'static,
2103{
2104}
2105
2106impl<W, S> From<EcsApp<W, S>> for LeakedEcsApp
2107where
2108 W: Work + 'static,
2109 S: BuildHasher + Default + 'static,
2110{
2111 fn from(value: EcsApp<W, S>) -> Self {
2112 LeakedEcsApp::new(value)
2113 }
2114}
2115
2116pub struct LeakedEcsApp {
2125 this: Ecs<'static>,
2126 drop: unsafe fn(Ecs<'static>),
2127}
2128
2129impl LeakedEcsApp {
2130 fn new<W, S>(app: EcsApp<W, S>) -> Self
2131 where
2132 W: Work + 'static,
2133 S: BuildHasher + Default + 'static,
2134 {
2135 unsafe fn _drop<W, S>(ecs: Ecs<'static>)
2136 where
2137 W: Work + 'static,
2138 S: BuildHasher + Default + 'static,
2139 {
2140 let ptr = ecs.this.cast::<EcsApp<W, S>>();
2141 let boxed_ecs = unsafe { Box::from_raw(ptr.as_ptr()) };
2142 drop(boxed_ecs);
2143 }
2144
2145 Self {
2146 this: Ecs::new(Box::leak(Box::new(app))),
2147 drop: _drop::<W, S>,
2148 }
2149 }
2150
2151 #[cfg(target_arch = "wasm32")]
2155 pub(crate) unsafe fn get(&self) -> EcsExt<'static> {
2156 EcsExt {
2157 ecs: self.this.copy(),
2158 }
2159 }
2160}
2161
2162impl Drop for LeakedEcsApp {
2163 fn drop(&mut self) {
2164 unsafe { (self.drop)(self.this.copy()) };
2169 }
2170}
2171
2172impl Deref for LeakedEcsApp {
2173 type Target = Ecs<'static>;
2174
2175 fn deref(&self) -> &Self::Target {
2176 &self.this
2177 }
2178}
2179
2180impl DerefMut for LeakedEcsApp {
2181 fn deref_mut(&mut self) -> &mut Self::Target {
2182 &mut self.this
2183 }
2184}
2185
2186#[repr(transparent)]
2188pub struct EcsExt<'ecs> {
2189 ecs: Ecs<'ecs>,
2190}
2191
2192impl EcsExt<'_> {
2193 pub fn step(&mut self) {
2198 unsafe {
2199 let vtable = self.ecs.vtable.as_ref();
2200 (vtable.step)(self.ecs.this);
2201 }
2202 }
2203}
2204
2205impl EcsEntry for EcsExt<'_> {
2206 fn add_system<T, Sys>(
2207 &mut self,
2208 desc: T,
2209 ) -> WithResult<&mut Self, SystemId, EcsError<SystemDesc<Sys>>>
2210 where
2211 T: Into<SystemDesc<Sys>>,
2212 Sys: System,
2213 {
2214 let res = self.ecs.add_system(desc).take();
2215 WithResult::new(self, res)
2216 }
2217
2218 fn add_once_system<T, Req, F>(
2219 &mut self,
2220 sys: T,
2221 ) -> WithResult<&mut Self, SystemId, EcsError<SystemDesc<FnOnceSystem<Req, F>>>>
2222 where
2223 T: Into<FnOnceSystem<Req, F>>,
2224 FnOnceSystem<Req, F>: System,
2225 {
2226 let res = self.ecs.add_once_system(sys).take();
2227 WithResult::new(self, res)
2228 }
2229
2230 fn unregister_system(&mut self, sid: SystemId) -> WithResult<&mut Self, (), EcsError> {
2231 let res = self.ecs.unregister_system(sid).take();
2232 WithResult::new(self, res)
2233 }
2234
2235 fn activate_system(
2236 &mut self,
2237 target: SystemId,
2238 at: InsertPos,
2239 live: Tick,
2240 ) -> WithResult<&mut Self, (), EcsError> {
2241 let res = self.ecs.activate_system(target, at, live).take();
2242 WithResult::new(self, res)
2243 }
2244
2245 fn inactivate_system(&mut self, sid: SystemId) -> WithResult<&mut Self, (), EcsError> {
2246 let res = self.ecs.inactivate_system(sid).take();
2247 WithResult::new(self, res)
2248 }
2249
2250 fn register_entity(&mut self, desc: EntityReg) -> WithResult<&mut Self, EntityIndex, EcsError> {
2251 let res = self.ecs.register_entity(desc).take();
2252 WithResult::new(self, res)
2253 }
2254
2255 fn unregister_entity<C>(&mut self) -> WithResult<&mut Self, Box<dyn ContainEntity>, EcsError>
2256 where
2257 C: Components,
2258 {
2259 let res = self.ecs.unregister_entity::<C>().take();
2260 WithResult::new(self, res)
2261 }
2262
2263 fn add_entity<E>(
2264 &mut self,
2265 ei: EntityIndex,
2266 value: E,
2267 ) -> WithResult<&mut Self, EntityId, EcsError<E>>
2268 where
2269 E: Entity,
2270 {
2271 let res = self.ecs.add_entity(ei, value).take();
2272 WithResult::new(self, res)
2273 }
2274
2275 fn remove_entity(&mut self, eid: EntityId) -> WithResult<&mut Self, (), EcsError> {
2276 let res = self.ecs.remove_entity(eid).take();
2277 WithResult::new(self, res)
2278 }
2279
2280 fn add_resource<T>(
2281 &mut self,
2282 desc: T,
2283 ) -> WithResult<&mut Self, ResourceIndex, EcsError<ResourceDesc>>
2284 where
2285 T: Into<ResourceDesc>,
2286 {
2287 let res = self.ecs.add_resource(desc).take();
2288 WithResult::new(self, res)
2289 }
2290
2291 fn remove_resource<R>(&mut self) -> WithResult<&mut Self, Option<R>, EcsError>
2292 where
2293 R: Resource,
2294 {
2295 let res = self.ecs.remove_resource::<R>().take();
2296 WithResult::new(self, res)
2297 }
2298
2299 fn get_resource<R>(&self) -> Option<&R>
2300 where
2301 R: Resource,
2302 {
2303 self.ecs.get_resource()
2304 }
2305
2306 fn get_resource_mut<R>(&mut self) -> Option<&mut R>
2307 where
2308 R: Resource,
2309 {
2310 self.ecs.get_resource_mut()
2311 }
2312
2313 fn get_resource_index<R>(&self) -> Option<ResourceIndex>
2314 where
2315 R: Resource,
2316 {
2317 self.ecs.get_resource_index::<R>()
2318 }
2319
2320 fn execute_commands<T>(
2321 &mut self,
2322 cmds: T,
2323 ) -> WithResult<&mut Self, (), Box<dyn Error + Send + Sync + 'static>>
2324 where
2325 T: HelpExecuteManyCommands,
2326 {
2327 let res = self.ecs.execute_commands(cmds).take();
2328 WithResult::new(self, res)
2329 }
2330
2331 fn execute_command<F, R>(
2332 &mut self,
2333 f: F,
2334 ) -> WithResult<&mut Self, (), Box<dyn Error + Send + Sync + 'static>>
2335 where
2336 F: FnOnce(Commander) -> R,
2337 R: Command,
2338 {
2339 let res = self.ecs.execute_command(f).take();
2340 WithResult::new(self, res)
2341 }
2342
2343 fn errors(&mut self) -> Vec<Box<dyn Error + Send + Sync + 'static>> {
2344 self.ecs.errors()
2345 }
2346}
2347
2348#[cfg(test)]
2349mod tests {
2350 use crate as my_ecs;
2351 use crate::prelude::*;
2352 use std::sync::{Arc, Mutex};
2353
2354 #[test]
2355 fn test_add_many_systems() {
2356 let mut ecs = Ecs::default(WorkerPool::with_len(1), [1]);
2357
2358 let state = Arc::new(Mutex::new(vec![]));
2359
2360 struct StructSystem(Arc<Mutex<Vec<i32>>>);
2362 request!(Req);
2363 impl System for StructSystem {
2364 type Request = Req;
2365 fn run(&mut self, _resp: Response<'_, Self::Request>) {
2366 self.0.lock().unwrap().push(0);
2367 }
2368 }
2369 let sys0 = StructSystem(Arc::clone(&state));
2370
2371 let c_state = Arc::clone(&state);
2373 let sys1 = move || {
2374 c_state.lock().unwrap().push(1);
2375 };
2376
2377 ecs.add_systems((sys0, sys1)).step();
2378
2379 assert_eq!(*state.lock().unwrap(), vec![0, 1]);
2380 }
2381
2382 #[test]
2383 fn test_execute_many_commands() {
2384 let mut ecs = Ecs::default(WorkerPool::with_len(1), [1]);
2385
2386 let state = Arc::new(Mutex::new(vec![]));
2387
2388 struct StructCommand(Arc<Mutex<Vec<i32>>>);
2390 impl Command for StructCommand {
2391 fn command(&mut self, _ecs: Ecs<'_>) -> DynResult<()> {
2392 self.0.lock().unwrap().push(0);
2393 Ok(())
2394 }
2395 }
2396 let cmd0 = StructCommand(Arc::clone(&state));
2397
2398 let c_state = Arc::clone(&state);
2400 let cmd1 = move |_ecs: Ecs| {
2401 c_state.lock().unwrap().push(1);
2402 Ok(())
2403 };
2404
2405 ecs.execute_commands((cmd0, Some(cmd1))).unwrap();
2406
2407 assert_eq!(*state.lock().unwrap(), vec![0, 1]);
2408 }
2409
2410 #[test]
2411 fn test_add_many_resources() {
2412 use crate as my_ecs;
2413 let mut ecs = Ecs::default(WorkerPool::with_len(1), [1]);
2414
2415 #[derive(Resource)]
2417 struct Ra(i32);
2418 #[derive(Resource)]
2419 struct Rb(String);
2420
2421 let ra = Ra(0);
2422 let rb = Rb("b".to_owned());
2423 ecs.add_resources((ra, rb))
2424 .add_once_system(|rr: ResRead<(Ra, Rb)>| {
2425 let (a, b) = rr.0;
2426 assert_eq!(a.0, 0);
2427 assert_eq!(&b.0, "b");
2428 })
2429 .step();
2430
2431 assert!(ecs.collect_poisoned_systems().is_empty());
2432 }
2433
2434 #[test]
2435 fn test_zero_workers() {
2436 let cnt = Arc::new(Mutex::new(0));
2437 let cnt0 = Arc::clone(&cnt);
2438 let cnt1 = Arc::clone(&cnt);
2439
2440 Ecs::default(WorkerPool::new(), [])
2441 .add_once_systems((
2442 move || *cnt0.lock().unwrap() += 1,
2443 move || *cnt1.lock().unwrap() += 10,
2444 ))
2445 .step();
2446
2447 assert_eq!(*cnt.lock().unwrap(), 11);
2448 }
2449
2450 #[test]
2451 fn test_multiple_apps() {
2452 let mut a = Ecs::default(WorkerPool::with_len(1), [1]);
2453 let mut b = Ecs::default(WorkerPool::new(), []);
2454
2455 let cnt = Arc::new(Mutex::new(0));
2456 let cnt_a = Arc::clone(&cnt);
2457 let cnt_b = Arc::clone(&cnt);
2458
2459 a.add_once_system(move || *cnt_a.lock().unwrap() += 1)
2460 .unwrap();
2461 b.add_once_system(move || *cnt_b.lock().unwrap() += 10)
2462 .unwrap();
2463
2464 a.step();
2465 assert_eq!(*cnt.lock().unwrap(), 1);
2466 drop(a);
2467
2468 b.step();
2469 assert_eq!(*cnt.lock().unwrap(), 11);
2470 drop(b);
2471 }
2472}