1use crate::{
2 state::{Dependency, DynState, GetStateId, State, StateId, TypedStateId},
3 unique_id, AnyCompose, ChildIndex, StateChanged,
4};
5use bevy_ecs::{
6 entity::Entity,
7 system::{BoxedSystem, IntoSystem},
8};
9use std::{
10 any::Any,
11 fmt::{Debug, Display},
12 sync::Arc,
13};
14
15#[derive(Default, Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
16pub struct ScopeId(usize);
17
18pub struct Scope<'a> {
22 pub(crate) id: ScopeId,
23
24 pub(crate) index: usize,
27
28 pub(crate) child_index: ChildIndex,
30
31 pub(crate) entity: Option<Entity>,
33
34 pub(crate) parent_entity: Entity,
36
37 pub(crate) will_decompose: bool,
39
40 pub(crate) composer: Arc<dyn AnyCompose + 'a>,
43
44 pub(crate) state_index: usize,
46
47 pub(crate) states: Vec<DynState>,
49
50 pub(crate) children: Vec<Scope<'a>>,
52
53 pub(crate) queued_systems: Vec<BoxedSystem<(), ()>>,
56}
57
58impl Debug for Scope<'_> {
59 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
60 fmt_scope_with_indents(self, f, 0)
61 }
62}
63
64fn fmt_scope_with_indents(
65 scope: &Scope,
66 f: &mut std::fmt::Formatter,
67 level: usize,
68) -> std::fmt::Result {
69 let indents = " ".repeat(level);
70 let name = scope.composer.get_name();
71
72 if scope.children.is_empty() {
73 return writeln!(f, "{}<{} id={{{}}}/>", indents, name, scope.id.0);
74 }
75
76 writeln!(f, "{}<{} id={{{}}}>", indents, name, scope.id.0)?;
77
78 for child in scope.children.iter() {
79 fmt_scope_with_indents(child, f, level + 1)?;
80 }
81
82 writeln!(f, "{}</{}>", indents, name)
83}
84
85impl Display for Scope<'_> {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 let name = self.composer.get_name();
88 write!(f, "Scope(name: {}, id: {})", name, self.id.0)
89 }
90}
91
92impl Scope<'_> {
93 pub(crate) fn new(
94 composer: Arc<dyn AnyCompose>,
95 index: usize,
96 parent_entity: Entity,
97 mut parent_child_index: ChildIndex,
98 ) -> Self {
99 parent_child_index.push(index);
100
101 Self {
102 id: ScopeId(unique_id()),
103 index,
104 child_index: parent_child_index,
105 entity: None,
106 parent_entity,
107 will_decompose: false,
108 composer: composer.clone(),
109 state_index: 0,
110 states: Vec::new(),
111 children: Vec::new(),
112 queued_systems: Vec::new(),
113 }
114 }
115
116 pub(crate) fn as_root_scope(entity: Entity, composer: Arc<dyn AnyCompose>) -> Self {
117 Self {
118 id: ScopeId(unique_id()),
119 index: 0,
120 child_index: ChildIndex::new(0),
121 entity: Some(entity),
122 parent_entity: entity,
123 will_decompose: false,
124 composer: composer.clone(),
125 state_index: 0,
126 states: Vec::new(),
127 children: Vec::new(),
128 queued_systems: Vec::new(),
129 }
130 }
131
132 pub fn use_state<T: Any + Send + Sync>(&mut self, initial_value: T) -> State<T> {
135 if let Some(existing_state) = self.states.get(self.state_index) {
136 self.state_index += 1;
137 return existing_state.to_state::<T>();
138 }
139
140 let value = Arc::new(initial_value);
141
142 let dyn_state = DynState {
143 id: StateId::Generated(unique_id()),
144 changed: StateChanged::Changed,
145 value: value.clone(),
146 };
147
148 let state = dyn_state.to_state();
149
150 self.states.push(dyn_state);
151 self.state_index += 1;
152
153 state
154 }
155
156 pub fn use_state_with_id<T: Any + Send + Sync>(
159 &mut self,
160 state_id: TypedStateId<T>,
161 initial_value: T,
162 ) -> State<T> {
163 if let Some(existing_state) = self.states.iter().find(|s| s.id == state_id.get_id()) {
164 self.state_index += 1;
165 return existing_state.to_state::<T>();
166 }
167
168 let value = Arc::new(initial_value);
169
170 let dyn_state = DynState {
171 id: state_id.get_id(),
172 changed: StateChanged::Changed,
173 value: value.clone(),
174 };
175
176 let state = dyn_state.to_state();
177
178 self.states.push(dyn_state);
179 self.state_index += 1;
180
181 state
182 }
183
184 pub fn set_state<T: Send + Sync + 'static>(&mut self, state: impl GetStateId<T>, value: T) {
186 let state = self
187 .states
188 .iter_mut()
189 .find(|s| s.id == state.get_id())
190 .unwrap_or_else(|| panic!("State not found."));
191
192 if !state.value.is::<T>() {
193 panic!("State value type mismatch.");
194 }
195
196 state.value = Arc::new(value);
197 state.changed = StateChanged::Queued;
198 }
199
200 pub fn set_state_unchanged<T: Send + Sync + 'static>(
202 &mut self,
203 state: impl GetStateId<T>,
204 value: T,
205 ) {
206 let state = self
207 .states
208 .iter_mut()
209 .find(|s| s.id == state.get_id())
210 .unwrap_or_else(|| panic!("State not found."));
211
212 if !state.value.is::<T>() {
213 panic!("State value type mismatch.");
214 }
215
216 state.value = Arc::new(value);
217 }
218
219 pub(crate) fn get_state_by_index<T: Any + Send + Sync>(&self, index: usize) -> State<T> {
220 let dyn_state = self
221 .states
222 .get(index)
223 .unwrap_or_else(|| panic!("State not found."));
224
225 dyn_state.to_state()
226 }
227
228 pub fn effect(&mut self, effect: impl Fn(), dependecies: impl Dependency) {
230 if !dependecies.has_changed() {
231 return;
232 }
233
234 effect();
235 }
236
237 pub fn use_mount(&mut self, callback: impl Fn()) {
239 let once = self.use_state(());
240 self.effect(callback, once);
241 }
242
243 pub fn run_system<M>(&mut self, system: impl IntoSystem<(), (), M>) {
246 let sys: BoxedSystem<(), ()> = Box::from(IntoSystem::into_system(system));
247 self.queued_systems.push(sys);
248 }
249
250 pub fn use_system_once<M>(&mut self, system: impl IntoSystem<(), (), M>) {
252 let once = self.use_state(());
253
254 if matches!(once.changed, StateChanged::Changed) {
255 self.run_system(system);
256 }
257 }
258
259 pub(crate) fn set_entity(&mut self, entity: Entity) {
260 self.entity = Some(entity);
261 }
262}