1use std::{
2 any::{
3 Any,
4 TypeId,
5 },
6 collections::BTreeMap,
7 marker::PhantomData,
8 ops::Deref,
9 sync::Arc,
10};
11
12use parking_lot::RwLock;
13use rustc_hash::{
14 FxHashMap,
15 FxHashSet,
16};
17use shipyard::{
18 Borrow,
19 BorrowInfo,
20 Component,
21 Unique,
22 UniqueView,
23 View,
24 WorkloadSystem,
25};
26
27use crate::{
28 node::{
29 FromAnyValue,
30 NodeType,
31 },
32 node_ref::{
33 NodeMaskBuilder,
34 NodeView,
35 },
36 real_dom::SendAnyMapWrapper,
37 tree::{
38 TreeRef,
39 TreeRefView,
40 },
41 NodeId,
42 NodeMask,
43 SendAnyMap,
44};
45
46#[derive(Default)]
47struct DirtyNodes {
48 nodes_dirty: FxHashSet<NodeId>,
49}
50
51impl DirtyNodes {
52 pub fn add_node(&mut self, node_id: NodeId) {
53 self.nodes_dirty.insert(node_id);
54 }
55
56 pub fn is_empty(&self) -> bool {
57 self.nodes_dirty.is_empty()
58 }
59
60 pub fn pop(&mut self) -> Option<NodeId> {
61 self.nodes_dirty.iter().next().copied().inspect(|id| {
62 self.nodes_dirty.remove(id);
63 })
64 }
65}
66
67#[derive(Clone, Unique)]
69pub struct DirtyNodeStates {
70 dirty: Arc<FxHashMap<TypeId, RwLock<BTreeMap<u16, DirtyNodes>>>>,
71}
72
73impl DirtyNodeStates {
74 pub fn with_passes(passes: impl Iterator<Item = TypeId>) -> Self {
75 Self {
76 dirty: Arc::new(
77 passes
78 .map(|pass| (pass, RwLock::new(BTreeMap::new())))
79 .collect(),
80 ),
81 }
82 }
83
84 pub fn insert(&self, pass_id: TypeId, node_id: NodeId, height: u16) {
85 if let Some(btree) = self.dirty.get(&pass_id) {
86 let mut write = btree.write();
87 if let Some(entry) = write.get_mut(&height) {
88 entry.add_node(node_id);
89 } else {
90 let mut entry = DirtyNodes::default();
91 entry.add_node(node_id);
92 write.insert(height, entry);
93 }
94 }
95 }
96
97 fn pop_front(&self, pass_id: TypeId) -> Option<(u16, NodeId)> {
98 let mut values = self.dirty.get(&pass_id)?.write();
99 let mut value = values.first_entry()?;
100 let height = *value.key();
101 let ids = value.get_mut();
102 let id = ids.pop()?;
103 if ids.is_empty() {
104 value.remove_entry();
105 }
106
107 Some((height, id))
108 }
109
110 fn pop_back(&self, pass_id: TypeId) -> Option<(u16, NodeId)> {
111 let mut values = self.dirty.get(&pass_id)?.write();
112 let mut value = values.last_entry()?;
113 let height = *value.key();
114 let ids = value.get_mut();
115 let id = ids.pop()?;
116 if ids.is_empty() {
117 value.remove_entry();
118 }
119
120 Some((height, id))
121 }
122}
123
124pub trait State<V: FromAnyValue + Send + Sync = ()>: Any + Send + Sync {
126 type ParentDependencies: Dependancy;
128 type ChildDependencies: Dependancy;
130 type NodeDependencies: Dependancy;
132 const NODE_MASK: NodeMaskBuilder<'static>;
134
135 const TRAVERSE_SHADOW_DOM: bool = false;
137
138 fn allow_node(node_type: &NodeType<V>) -> bool {
140 !node_type.is_text()
141 }
142
143 fn update<'a>(
145 &mut self,
146 node_view: NodeView<V>,
147 node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
148 parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
149 children: Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
150 context: &SendAnyMap,
151 ) -> bool;
152
153 fn create<'a>(
155 node_view: NodeView<V>,
156 node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
157 parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
158 children: Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
159 context: &SendAnyMap,
160 ) -> Self;
161
162 fn workload_system(
164 type_id: TypeId,
165 dependants: Arc<Dependants>,
166 pass_direction: PassDirection,
167 ) -> WorkloadSystem;
168
169 fn to_type_erased() -> TypeErasedState<V>
171 where
172 Self: Sized,
173 {
174 let node_mask = Self::NODE_MASK.build();
175 TypeErasedState {
176 this_type_id: TypeId::of::<Self>(),
177 parent_dependancies_ids: Self::ParentDependencies::type_ids()
178 .iter()
179 .copied()
180 .collect(),
181 child_dependancies_ids: Self::ChildDependencies::type_ids()
182 .iter()
183 .copied()
184 .collect(),
185 node_dependancies_ids: Self::NodeDependencies::type_ids().iter().copied().collect(),
186 dependants: Default::default(),
187 mask: node_mask,
188 pass_direction: pass_direction::<V, Self>(),
189 enter_shadow_dom: Self::TRAVERSE_SHADOW_DOM,
190 workload: Self::workload_system,
191 phantom: PhantomData,
192 }
193 }
194}
195
196fn pass_direction<V: FromAnyValue + Send + Sync, S: State<V>>() -> PassDirection {
197 if S::ChildDependencies::type_ids()
198 .iter()
199 .any(|type_id| *type_id == TypeId::of::<S>())
200 {
201 PassDirection::ChildToParent
202 } else if S::ParentDependencies::type_ids()
203 .iter()
204 .any(|type_id| *type_id == TypeId::of::<S>())
205 {
206 PassDirection::ParentToChild
207 } else {
208 PassDirection::AnyOrder
209 }
210}
211
212#[doc(hidden)]
213#[derive(Borrow, BorrowInfo)]
214pub struct RunPassView<'a, V: FromAnyValue + Send + Sync = ()> {
215 pub tree: TreeRefView<'a>,
216 pub node_type: View<'a, NodeType<V>>,
217 node_states: UniqueView<'a, DirtyNodeStates>,
218 any_map: UniqueView<'a, SendAnyMapWrapper>,
219}
220
221#[doc(hidden)]
224pub fn run_pass<V: FromAnyValue + Send + Sync>(
225 type_id: TypeId,
226 dependants: &Dependants,
227 pass_direction: PassDirection,
228 view: RunPassView<V>,
229 mut update_node: impl FnMut(NodeId, &SendAnyMap, u16) -> bool,
230) {
231 let RunPassView {
232 tree,
233 node_states: dirty,
234 any_map: ctx,
235 ..
236 } = view;
237 let ctx = ctx.as_ref();
238 match pass_direction {
239 PassDirection::ParentToChild => {
240 while let Some((height, id)) = dirty.pop_front(type_id) {
241 if (update_node)(id, ctx, height) {
242 dependants.mark_dirty(&dirty, id, &tree, height);
243 }
244 }
245 }
246 PassDirection::ChildToParent => {
247 while let Some((height, id)) = dirty.pop_back(type_id) {
248 if (update_node)(id, ctx, height) {
249 dependants.mark_dirty(&dirty, id, &tree, height);
250 }
251 }
252 }
253 PassDirection::AnyOrder => {
254 while let Some((height, id)) = dirty.pop_back(type_id) {
255 if (update_node)(id, ctx, height) {
256 dependants.mark_dirty(&dirty, id, &tree, height);
257 }
258 }
259 }
260 }
261}
262
263#[derive(Debug, Clone, Copy, PartialEq, Eq)]
264pub(crate) struct Dependant {
265 pub(crate) type_id: TypeId,
266 pub(crate) enter_shadow_dom: bool,
267}
268
269#[derive(Default, Debug, Clone, PartialEq, Eq)]
271pub struct Dependants {
272 pub(crate) parent: Vec<Dependant>,
274 pub(crate) child: Vec<Dependant>,
276 pub(crate) node: Vec<TypeId>,
278}
279
280impl Dependants {
281 fn mark_dirty(&self, dirty: &DirtyNodeStates, id: NodeId, tree: &impl TreeRef, height: u16) {
282 for &Dependant {
283 type_id,
284 enter_shadow_dom,
285 } in &self.child
286 {
287 for id in tree.children_ids_advanced(id, enter_shadow_dom) {
288 dirty.insert(type_id, id, height + 1);
289 }
290 }
291
292 for &Dependant {
293 type_id,
294 enter_shadow_dom,
295 } in &self.parent
296 {
297 if let Some(id) = tree.parent_id_advanced(id, enter_shadow_dom) {
298 dirty.insert(type_id, id, height - 1);
299 }
300 }
301
302 for dependant in &self.node {
303 dirty.insert(*dependant, id, height);
304 }
305 }
306}
307
308pub struct TypeErasedState<V: FromAnyValue + Send = ()> {
310 pub(crate) this_type_id: TypeId,
311 pub(crate) parent_dependancies_ids: FxHashSet<TypeId>,
312 pub(crate) child_dependancies_ids: FxHashSet<TypeId>,
313 pub(crate) node_dependancies_ids: FxHashSet<TypeId>,
314 pub(crate) dependants: Arc<Dependants>,
315 pub(crate) mask: NodeMask,
316 pub(crate) workload: fn(TypeId, Arc<Dependants>, PassDirection) -> WorkloadSystem,
317 pub(crate) pass_direction: PassDirection,
318 pub(crate) enter_shadow_dom: bool,
319 phantom: PhantomData<V>,
320}
321
322impl<V: FromAnyValue + Send> TypeErasedState<V> {
323 pub(crate) fn create_workload(&self) -> WorkloadSystem {
324 (self.workload)(
325 self.this_type_id,
326 self.dependants.clone(),
327 self.pass_direction,
328 )
329 }
330
331 pub(crate) fn combined_dependancy_type_ids(&self) -> impl Iterator<Item = TypeId> + '_ {
332 self.parent_dependancies_ids
333 .iter()
334 .chain(self.child_dependancies_ids.iter())
335 .chain(self.node_dependancies_ids.iter())
336 .copied()
337 }
338}
339
340#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
342pub enum PassDirection {
343 ParentToChild,
345 ChildToParent,
347 AnyOrder,
349}
350
351pub trait Dependancy {
353 type ElementBorrowed<'a>;
355
356 fn type_ids() -> Box<[TypeId]> {
358 Box::new([])
359 }
360}
361
362macro_rules! impl_dependancy {
363 ($($t:ident),*) => {
364 impl< $($t: Send + Sync + Component),* > Dependancy for ($($t,)*) {
365 type ElementBorrowed<'a> = ($(DependancyView<'a, $t>,)*);
366
367 fn type_ids() -> Box<[TypeId]> {
368 Box::new([$(TypeId::of::<$t>()),*])
369 }
370 }
371 };
372}
373
374pub struct DependancyView<'a, T> {
378 inner: &'a T,
379}
380
381impl<'a, T> DependancyView<'a, T> {
382 #[doc(hidden)]
384 pub fn new(inner: &'a T) -> Self {
385 Self { inner }
386 }
387}
388
389impl<T> Deref for DependancyView<'_, T> {
390 type Target = T;
391
392 fn deref(&self) -> &Self::Target {
393 self.inner
394 }
395}
396
397impl_dependancy!();
398impl_dependancy!(A);
399impl_dependancy!(A, B);
400impl_dependancy!(A, B, C);
401impl_dependancy!(A, B, C, D);
402impl_dependancy!(A, B, C, D, E);
403impl_dependancy!(A, B, C, D, E, F);
404impl_dependancy!(A, B, C, D, E, F, G);
405impl_dependancy!(A, B, C, D, E, F, G, H);
406impl_dependancy!(A, B, C, D, E, F, G, H, I);
407impl_dependancy!(A, B, C, D, E, F, G, H, I, J);