1use std::{
2 any::TypeId,
3 cell::RefCell,
4 cmp::Ordering,
5 collections::{
6 HashMap,
7 VecDeque,
8 },
9 fmt::Debug,
10 rc::Rc,
11 sync::atomic::AtomicU64,
12};
13
14use futures_lite::{
15 FutureExt,
16 StreamExt,
17};
18use itertools::Itertools;
19use pathgraph::PathGraph;
20use rustc_hash::{
21 FxHashMap,
22 FxHashSet,
23};
24
25use crate::{
26 current_context::CurrentContext,
27 diff_key::DiffKey,
28 element::{
29 Element,
30 ElementExt,
31 EventHandlerType,
32 },
33 events::{
34 data::{
35 Event,
36 EventType,
37 },
38 name::EventName,
39 },
40 node_id::NodeId,
41 path_element::PathElement,
42 prelude::{
43 Task,
44 TaskId,
45 },
46 reactive_context::ReactiveContext,
47 scope::{
48 PathNode,
49 Scope,
50 ScopeStorage,
51 },
52 scope_id::ScopeId,
53 tree::DiffModifies,
54};
55
56#[derive(Debug, PartialEq)]
57pub enum MutationRemove {
58 Element { id: NodeId, index: u32 },
60 Scope { id: NodeId },
62}
63
64impl MutationRemove {
65 pub fn node_id(&self) -> NodeId {
66 match self {
67 Self::Element { id, .. } => *id,
68 Self::Scope { id } => *id,
69 }
70 }
71}
72
73#[derive(Default)]
74pub struct Mutations {
75 pub added: Vec<(NodeId, NodeId, u32, Rc<dyn ElementExt>)>,
76 pub modified: Vec<(NodeId, Rc<dyn ElementExt>, DiffModifies)>,
77 pub removed: Vec<MutationRemove>,
78 pub moved: HashMap<NodeId, Vec<(u32, NodeId)>>,
79}
80
81impl Debug for Mutations {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 f.write_fmt(format_args!(
84 "Added: {:?} Modified: {:?} Removed: {:?} Moved: {:?}",
85 self.added
86 .iter()
87 .map(|(a, b, c, _)| (*a, *b, *c))
88 .collect::<Vec<_>>(),
89 self.modified.iter().map(|(a, _, _)| *a).collect::<Vec<_>>(),
90 self.removed,
91 self.moved
92 ))
93 }
94}
95
96pub enum Message {
97 MarkScopeAsDirty(ScopeId),
98 PollTask(TaskId),
99}
100
101pub struct Runner {
102 pub scopes: FxHashMap<ScopeId, Rc<RefCell<Scope>>>,
103 pub scopes_storages: Rc<RefCell<FxHashMap<ScopeId, ScopeStorage>>>,
104
105 pub(crate) dirty_scopes: FxHashSet<ScopeId>,
106 pub(crate) dirty_tasks: VecDeque<TaskId>,
107
108 pub(crate) node_to_scope: FxHashMap<NodeId, ScopeId>,
109
110 pub(crate) node_id_counter: NodeId,
111 pub(crate) scope_id_counter: ScopeId,
112 pub(crate) task_id_counter: Rc<AtomicU64>,
113
114 pub(crate) tasks: Rc<RefCell<FxHashMap<TaskId, Rc<RefCell<Task>>>>>,
115
116 pub(crate) sender: futures_channel::mpsc::UnboundedSender<Message>,
117 pub(crate) receiver: futures_channel::mpsc::UnboundedReceiver<Message>,
118}
119
120impl Drop for Runner {
121 fn drop(&mut self) {
122 for (scope_id, _scope) in self
124 .scopes
125 .drain()
126 .sorted_by_key(|s| s.1.borrow().height)
127 .rev()
128 {
129 CurrentContext::run_with_reactive(
130 CurrentContext {
131 scope_id,
132 scopes_storages: self.scopes_storages.clone(),
133 tasks: self.tasks.clone(),
134 task_id_counter: self.task_id_counter.clone(),
135 sender: self.sender.clone(),
136 },
137 || {
138 let _scope = self.scopes_storages.borrow_mut().remove(&scope_id);
139 },
140 );
141 }
142 }
143}
144
145impl Runner {
146 pub fn new(root: impl Fn() -> Element + 'static) -> Self {
147 let (sender, receiver) = futures_channel::mpsc::unbounded::<Message>();
148 Self {
149 scopes: FxHashMap::from_iter([(
150 ScopeId::ROOT,
151 Rc::new(RefCell::new(Scope {
152 parent_node_id_in_parent: NodeId::ROOT,
153 path_in_parent: Box::from([]),
154 height: 0,
155 parent_id: None,
156 id: ScopeId::ROOT,
157 key: DiffKey::Root,
158 comp: Rc::new(move |_| root()),
159 props: Rc::new(()),
160 element: None,
161 nodes: {
162 let mut map = PathGraph::new();
163 map.insert(
164 &[],
165 PathNode {
166 node_id: NodeId::ROOT,
167 scope_id: None,
168 },
169 );
170 map
171 },
172 })),
173 )]),
174 scopes_storages: Rc::new(RefCell::new(FxHashMap::from_iter([(
175 ScopeId::ROOT,
176 ScopeStorage::new(None, |writer| {
177 ReactiveContext::new_for_scope(sender.clone(), ScopeId::ROOT, writer)
178 }),
179 )]))),
180
181 node_to_scope: FxHashMap::from_iter([(NodeId::ROOT, ScopeId::ROOT)]),
182
183 node_id_counter: NodeId::ROOT,
184 scope_id_counter: ScopeId::ROOT,
185 task_id_counter: Rc::default(),
186
187 dirty_tasks: VecDeque::default(),
188 dirty_scopes: FxHashSet::from_iter([ScopeId::ROOT]),
189
190 tasks: Rc::default(),
191
192 sender,
193 receiver,
194 }
195 }
196
197 #[cfg(all(debug_assertions, feature = "debug-integrity"))]
198 #[cfg_attr(feature = "hotpath", hotpath::measure)]
199 pub fn verify_scopes_integrity(&self) {
200 let mut visited = FxHashSet::default();
201 let size = self.scopes.len();
202 let mut buffer = vec![ScopeId::ROOT];
203 while let Some(scope_id) = buffer.pop() {
204 if visited.contains(&scope_id) {
205 continue;
206 }
207 visited.insert(scope_id);
208 let scope = self.scopes.get(&scope_id).unwrap();
209 let scope = scope.borrow();
210 if let Some(parent) = scope.parent_id {
211 buffer.push(parent);
212 }
213 scope.nodes.traverse(&[], |_, &PathNode { scope_id, .. }| {
214 if let Some(scope_id) = scope_id {
215 buffer.push(scope_id);
216 }
217 });
218 }
219 assert_eq!(size, visited.len())
220 }
221
222 pub fn provide_root_context<T: 'static + Clone>(&mut self, context: impl FnOnce() -> T) -> T {
223 CurrentContext::run(
224 CurrentContext {
225 scope_id: ScopeId::ROOT,
226 scopes_storages: self.scopes_storages.clone(),
227 tasks: self.tasks.clone(),
228 task_id_counter: self.task_id_counter.clone(),
229 sender: self.sender.clone(),
230 },
231 move || {
232 let context = context();
233 let mut scopes_storages = self.scopes_storages.borrow_mut();
234 let root_scope_storage = scopes_storages.get_mut(&ScopeId::ROOT).unwrap();
235 root_scope_storage
236 .contexts
237 .insert(TypeId::of::<T>(), Rc::new(context.clone()));
238
239 context
240 },
241 )
242 }
243
244 pub fn handle_event(
245 &mut self,
246 node_id: impl Into<NodeId>,
247 event_name: EventName,
248 event_type: EventType,
249 bubbles: bool,
250 ) -> bool {
251 let node_id = node_id.into();
252 #[cfg(debug_assertions)]
253 tracing::info!("Handling event {event_name:?} for {node_id:?}");
254 let propagate = Rc::new(RefCell::new(bubbles));
255 let default = Rc::new(RefCell::new(true));
256
257 let Some(scope_id) = self.node_to_scope.get(&node_id) else {
258 return false;
259 };
260 let Some(path) = self
261 .scopes
262 .get(scope_id)
263 .unwrap()
264 .borrow()
265 .nodes
266 .find_path(|value| {
267 value
268 == Some(&PathNode {
269 node_id,
270 scope_id: None,
271 })
272 })
273 else {
274 return false;
275 };
276
277 let mut current_target = Some((path, *scope_id));
278 while let Some((path, scope_id)) = current_target.take() {
279 let scope = self.scopes.get(&scope_id).cloned().unwrap();
280 scope.borrow().with_element(&path, |element| {
281 match element {
282 PathElement::Component { .. } => {
283 unreachable!()
284 }
285 PathElement::Element { element, .. } => {
286 CurrentContext::run(
287 CurrentContext {
288 scope_id,
289 scopes_storages: self.scopes_storages.clone(),
290 tasks: self.tasks.clone(),
291 task_id_counter: self.task_id_counter.clone(),
292 sender: self.sender.clone(),
293 },
294 || {
295 match &event_type {
296 EventType::Mouse(data) => {
297 let event_handlers = element.events_handlers();
298 if let Some(event_handlers) = event_handlers {
299 match event_handlers.get(&event_name) {
300 Some(EventHandlerType::Mouse(handler)) => {
301 handler.call(Event {
302 data: data.clone(),
303 propagate: propagate.clone(),
304 default: default.clone(),
305 });
306 }
307 Some(_) => unreachable!(),
308 _ => {}
309 }
310 }
311 }
312 EventType::Keyboard(data) => {
313 let event_handlers = element.events_handlers();
314 if let Some(event_handlers) = event_handlers {
315 match event_handlers.get(&event_name) {
316 Some(EventHandlerType::Keyboard(handler)) => {
317 handler.call(Event {
318 data: data.clone(),
319 propagate: propagate.clone(),
320 default: default.clone(),
321 });
322 }
323 Some(_) => unreachable!(),
324 _ => {}
325 }
326 }
327 }
328 EventType::Sized(data) => {
329 let event_handlers = element.events_handlers();
330 if let Some(event_handlers) = event_handlers {
331 match event_handlers.get(&event_name) {
332 Some(EventHandlerType::Sized(handler)) => {
333 handler.call(Event {
334 data: data.clone(),
335 propagate: propagate.clone(),
336 default: default.clone(),
337 });
338 }
339 Some(_) => unreachable!(),
340 _ => {}
341 }
342 }
343 }
344 EventType::Wheel(data) => {
345 let event_handlers = element.events_handlers();
346 if let Some(event_handlers) = event_handlers {
347 match event_handlers.get(&event_name) {
348 Some(EventHandlerType::Wheel(handler)) => {
349 handler.call(Event {
350 data: data.clone(),
351 propagate: propagate.clone(),
352 default: default.clone(),
353 });
354 }
355 Some(_) => unreachable!(),
356 _ => {}
357 }
358 }
359 }
360 EventType::Touch(data) => {
361 let event_handlers = element.events_handlers();
362 if let Some(event_handlers) = event_handlers {
363 match event_handlers.get(&event_name) {
364 Some(EventHandlerType::Touch(handler)) => {
365 handler.call(Event {
366 data: data.clone(),
367 propagate: propagate.clone(),
368 default: default.clone(),
369 });
370 }
371 Some(_) => unreachable!(),
372 _ => {}
373 }
374 }
375 }
376 EventType::Pointer(data) => {
377 let event_handlers = element.events_handlers();
378 if let Some(event_handlers) = event_handlers {
379 match event_handlers.get(&event_name) {
380 Some(EventHandlerType::Pointer(handler)) => {
381 handler.call(Event {
382 data: data.clone(),
383 propagate: propagate.clone(),
384 default: default.clone(),
385 });
386 }
387 Some(_) => unreachable!(),
388 _ => {}
389 }
390 }
391 }
392 EventType::File(data) => {
393 let event_handlers = element.events_handlers();
394 if let Some(event_handlers) = event_handlers {
395 match event_handlers.get(&event_name) {
396 Some(EventHandlerType::File(handler)) => {
397 handler.call(Event {
398 data: data.clone(),
399 propagate: propagate.clone(),
400 default: default.clone(),
401 });
402 }
403 Some(_) => unreachable!(),
404 _ => {}
405 }
406 }
407 }
408 EventType::ImePreedit(data) => {
409 let event_handlers = element.events_handlers();
410 if let Some(event_handlers) = event_handlers {
411 match event_handlers.get(&event_name) {
412 Some(EventHandlerType::ImePreedit(handler)) => {
413 handler.call(Event {
414 data: data.clone(),
415 propagate: propagate.clone(),
416 default: default.clone(),
417 });
418 }
419 Some(_) => unreachable!(),
420 _ => {}
421 }
422 }
423 }
424 }
425
426 if *propagate.borrow() {
428 if path.len() > 1 {
429 current_target
431 .replace((path[..path.len() - 1].to_vec(), scope_id));
432 } else {
433 let mut parent_scope_id = scope.borrow().parent_id;
434 loop {
436 if let Some(parent_id) = parent_scope_id.take() {
437 let parent_scope =
438 self.scopes.get(&parent_id).unwrap();
439 let path = parent_scope.borrow().nodes.find_path(
440 |value| {
441 value
442 == Some(&PathNode {
443 node_id: scope
444 .borrow()
445 .parent_node_id_in_parent,
446 scope_id: None,
447 })
448 },
449 );
450 if let Some(path) = path {
451 current_target.replace((path, parent_id));
452 break;
453 } else {
454 parent_scope_id =
455 parent_scope.borrow().parent_id;
456 }
457 } else {
458 return;
459 }
460 }
461 }
462 }
463 },
464 )
465 }
466 }
467 });
468 }
469 *default.borrow()
470 }
471
472 #[cfg_attr(feature = "hotpath", hotpath::measure)]
473 pub async fn handle_events(&mut self) {
474 loop {
475 while let Ok(Some(msg)) = self.receiver.try_next() {
476 match msg {
477 Message::MarkScopeAsDirty(scope_id) => {
478 self.dirty_scopes.insert(scope_id);
479 }
480 Message::PollTask(task_id) => {
481 self.dirty_tasks.push_back(task_id);
482 }
483 }
484 }
485
486 if !self.dirty_scopes.is_empty() {
487 return;
488 }
489
490 while let Some(task_id) = self.dirty_tasks.pop_front() {
491 let Some(task) = self.tasks.borrow().get(&task_id).cloned() else {
492 continue;
493 };
494 let mut task = task.borrow_mut();
495 let waker = task.waker.clone();
496
497 let mut cx = std::task::Context::from_waker(&waker);
498
499 CurrentContext::run(
500 {
501 let Some(scope) = self.scopes.get(&task.scope_id) else {
502 continue;
503 };
504 CurrentContext {
505 scope_id: scope.borrow().id,
506 scopes_storages: self.scopes_storages.clone(),
507 tasks: self.tasks.clone(),
508 task_id_counter: self.task_id_counter.clone(),
509 sender: self.sender.clone(),
510 }
511 },
512 || {
513 let poll_result = task.future.poll(&mut cx);
514 if poll_result.is_ready() {
515 self.tasks.borrow_mut().remove(&task_id);
516 }
517 },
518 );
519 }
520
521 if !self.dirty_scopes.is_empty() {
522 return;
523 }
524
525 while let Some(msg) = self.receiver.next().await {
526 match msg {
527 Message::MarkScopeAsDirty(scope_id) => {
528 self.dirty_scopes.insert(scope_id);
529 }
530 Message::PollTask(task_id) => {
531 self.dirty_tasks.push_back(task_id);
532 }
533 }
534 }
535 }
536 }
537
538 #[cfg_attr(feature = "hotpath", hotpath::measure)]
540 pub fn handle_events_immediately(&mut self) {
541 while let Ok(Some(msg)) = self.receiver.try_next() {
542 match msg {
543 Message::MarkScopeAsDirty(scope_id) => {
544 self.dirty_scopes.insert(scope_id);
545 }
546 Message::PollTask(task_id) => {
547 self.dirty_tasks.push_back(task_id);
548 }
549 }
550 }
551
552 if !self.dirty_scopes.is_empty() {
553 return;
554 }
555
556 while let Some(task_id) = self.dirty_tasks.pop_front() {
558 let Some(task) = self.tasks.borrow().get(&task_id).cloned() else {
559 continue;
560 };
561 let mut task = task.borrow_mut();
562 let waker = task.waker.clone();
563
564 let mut cx = std::task::Context::from_waker(&waker);
565
566 CurrentContext::run(
567 {
568 let Some(scope) = self.scopes.get(&task.scope_id) else {
569 continue;
570 };
571 CurrentContext {
572 scope_id: scope.borrow().id,
573 scopes_storages: self.scopes_storages.clone(),
574 tasks: self.tasks.clone(),
575 task_id_counter: self.task_id_counter.clone(),
576 sender: self.sender.clone(),
577 }
578 },
579 || {
580 let poll_result = task.future.poll(&mut cx);
581 if poll_result.is_ready() {
582 self.tasks.borrow_mut().remove(&task_id);
583 }
584 },
585 );
586 }
587 }
588
589 #[cfg(debug_assertions)]
590 pub fn print_metrics(&self) {
591 println!("dirty_scopes: {}", self.dirty_scopes.len());
592 println!("dirty_tasks: {}", self.dirty_tasks.len());
593 println!("node_to_scope: {}", self.node_to_scope.len());
594 println!("scopes: {}", self.scopes.len());
595 println!("scopes_storages: {}", self.scopes_storages.borrow().len());
596 println!("tasks: {}", self.tasks.borrow().len());
597 }
598
599 #[cfg_attr(feature = "hotpath", hotpath::measure)]
600 pub fn sync_and_update(&mut self) -> Mutations {
601 self.handle_events_immediately();
602 use itertools::Itertools;
603
604 #[cfg(all(debug_assertions, feature = "debug-integrity"))]
605 self.verify_scopes_integrity();
606
607 let mut mutations = Mutations::default();
608
609 let dirty_scopes = self
610 .dirty_scopes
611 .drain()
612 .filter_map(|id| self.scopes.get(&id).cloned())
613 .sorted_by_key(|s| s.borrow().height)
614 .map(|s| s.borrow().id)
615 .collect::<Box<[_]>>();
616
617 let mut visited_scopes = FxHashSet::default();
618
619 for scope_id in dirty_scopes {
620 if visited_scopes.contains(&scope_id) {
622 continue;
623 }
624
625 let Some(scope_rc) = self.scopes.get(&scope_id).cloned() else {
626 continue;
627 };
628
629 let scope_id = scope_rc.borrow().id;
630
631 let element = CurrentContext::run_with_reactive(
632 CurrentContext {
633 scope_id,
634 scopes_storages: self.scopes_storages.clone(),
635 tasks: self.tasks.clone(),
636 task_id_counter: self.task_id_counter.clone(),
637 sender: self.sender.clone(),
638 },
639 || {
640 let scope = scope_rc.borrow();
641 (scope.comp)(scope.props.clone())
642 },
643 );
644
645 let path_element = PathElement::from_element(vec![0], element);
646 let mut diff = Diff::default();
647 path_element.diff(scope_rc.borrow().element.as_ref(), &mut diff);
648
649 self.apply_diff(&scope_rc, diff, &mut mutations, &path_element);
650
651 self.run_scope(
652 &scope_rc,
653 &path_element,
654 &mut mutations,
655 &mut visited_scopes,
656 );
657
658 let mut scopes_storages = self.scopes_storages.borrow_mut();
659 let scope_storage = scopes_storages.get_mut(&scope_rc.borrow().id).unwrap();
660 scope_storage.current_value = 0;
661 scope_storage.current_run += 1;
662
663 scope_rc.borrow_mut().element = Some(path_element);
664 }
665
666 mutations
667 }
668
669 #[cfg_attr(feature = "hotpath", hotpath::measure)]
670 fn run_scope(
671 &mut self,
672 scope: &Rc<RefCell<Scope>>,
673 element: &PathElement,
674 mutations: &mut Mutations,
675 visited_scopes: &mut FxHashSet<ScopeId>,
676 ) {
677 visited_scopes.insert(scope.borrow().id);
678 match element {
679 PathElement::Component {
680 comp,
681 props,
682 key,
683 path,
684 } => {
685 let assigned_scope_id = scope
687 .borrow()
688 .nodes
689 .get(path)
690 .and_then(|path_node| path_node.scope_id)
691 .unwrap();
692
693 let parent_node_id = if path.as_ref() == [0] {
694 scope.borrow().parent_node_id_in_parent
695 } else {
696 scope
697 .borrow()
698 .nodes
699 .get(&path[..path.len() - 1])
700 .unwrap()
701 .node_id
702 };
703
704 if let Some(Ok(mut existing_scope)) = self
705 .scopes
706 .get(&assigned_scope_id)
707 .map(|s| s.try_borrow_mut())
708 {
709 let key_changed = existing_scope.key != *key;
710 if key_changed || existing_scope.props.changed(props.as_ref()) {
711 self.dirty_scopes.insert(assigned_scope_id);
712 existing_scope.props = props.clone();
713
714 if key_changed {
715 self.scopes_storages
716 .borrow_mut()
717 .get_mut(&assigned_scope_id)
718 .unwrap()
719 .reset();
720 }
721 }
722 } else {
723 self.scopes.insert(
724 assigned_scope_id,
725 Rc::new(RefCell::new(Scope {
726 parent_node_id_in_parent: parent_node_id,
727 path_in_parent: path.clone(),
728 height: scope.borrow().height + 1,
729 parent_id: Some(scope.borrow().id),
730 id: assigned_scope_id,
731 key: key.clone(),
732 comp: comp.clone(),
733 props: props.clone(),
734 element: None,
735 nodes: PathGraph::default(),
736 })),
737 );
738 self.scopes_storages.borrow_mut().insert(
739 assigned_scope_id,
740 ScopeStorage::new(Some(scope.borrow().id), |writer| {
741 ReactiveContext::new_for_scope(
742 self.sender.clone(),
743 assigned_scope_id,
744 writer,
745 )
746 }),
747 );
748 self.dirty_scopes.insert(assigned_scope_id);
749 }
750
751 let was_dirty = self.dirty_scopes.remove(&assigned_scope_id);
752
753 if !was_dirty {
754 return;
756 }
757
758 let scope_rc = self.scopes.get(&assigned_scope_id).cloned().unwrap();
759
760 let element = hotpath::measure_block!("Scope Rendering", {
761 CurrentContext::run_with_reactive(
762 CurrentContext {
763 scope_id: assigned_scope_id,
764 scopes_storages: self.scopes_storages.clone(),
765 tasks: self.tasks.clone(),
766 task_id_counter: self.task_id_counter.clone(),
767 sender: self.sender.clone(),
768 },
769 || {
770 let scope = scope_rc.borrow();
771 (scope.comp)(scope.props.clone())
772 },
773 )
774 });
775
776 let path_element = PathElement::from_element(vec![0], element);
777 let mut diff = Diff::default();
778 path_element.diff(scope_rc.borrow().element.as_ref(), &mut diff);
779
780 self.apply_diff(&scope_rc, diff, mutations, &path_element);
781
782 self.run_scope(&scope_rc, &path_element, mutations, visited_scopes);
783 let mut scopes_storages = self.scopes_storages.borrow_mut();
784 let scope_storage = scopes_storages.get_mut(&assigned_scope_id).unwrap();
785 scope_storage.current_value = 0;
786 scope_storage.current_run += 1;
787
788 scope_rc.borrow_mut().element = Some(path_element);
789 }
790 PathElement::Element { elements, .. } => {
791 for element in elements.iter() {
792 self.run_scope(scope, element, mutations, visited_scopes);
793 }
794 }
795 }
796 }
797
798 #[cfg_attr(feature = "hotpath", hotpath::measure)]
799 fn apply_diff(
800 &mut self,
801 scope: &Rc<RefCell<Scope>>,
802 diff: Diff,
803 mutations: &mut Mutations,
804 path_element: &PathElement,
805 ) {
806 let mut moved_nodes =
807 FxHashMap::<Box<[u32]>, (NodeId, FxHashMap<u32, PathNode>)>::default();
808 let mut parents_to_resync_scopes = FxHashSet::default();
809
810 for (parent, movements) in &diff.moved {
813 parents_to_resync_scopes.insert(parent.clone());
814 let paths = moved_nodes.entry(parent.clone()).or_insert_with(|| {
815 let parent_node_id = scope.borrow().nodes.get(parent).unwrap().node_id;
816 (parent_node_id, FxHashMap::default())
817 });
818
819 for (from, _to) in movements.iter() {
820 let mut path = parent.to_vec();
821 path.push(*from);
822
823 let path_node = scope.borrow().nodes.get(&path).cloned().unwrap();
824
825 paths.1.insert(*from, path_node);
826 }
827 }
828
829 let mut selected_roots: HashMap<Box<[u32]>, Vec<Box<[u32]>>> = HashMap::default();
831 let mut scope_removal_buffer = vec![];
832
833 'remove: for removed in diff.removed.iter().sorted_by(|a, b| {
853 for (x, y) in a.iter().zip(b.iter()) {
854 match x.cmp(y) {
855 Ordering::Equal => continue,
856 non_eq => return non_eq.reverse(),
857 }
858 }
859 b.len().cmp(&a.len())
860 }) {
861 parents_to_resync_scopes.insert(Box::from(&removed[..removed.len() - 1]));
862
863 let path_node = scope.borrow().nodes.get(removed).cloned();
864 if let Some(PathNode { node_id, scope_id }) = path_node {
865 if let Some(scope_id) = scope_id {
866 scope_removal_buffer.push(self.scopes.get(&scope_id).cloned().unwrap());
868 scope.borrow_mut().nodes.remove(removed);
869 } else {
870 mutations.removed.push(MutationRemove::Element {
872 id: node_id,
873 index: *removed.last().unwrap(),
874 });
875
876 for (root, inner) in &mut selected_roots {
878 if is_descendant(removed, root) {
879 inner.push(removed.clone());
880 continue 'remove;
881 }
882 }
883
884 selected_roots.retain(|root, _| !is_descendant(root, removed));
886
887 selected_roots
888 .entry(Box::from(&removed[..removed.len() - 1]))
889 .or_default()
890 .push(removed.clone());
891 }
892 } else {
893 unreachable!()
894 }
895 }
896
897 for (root, removed) in selected_roots {
899 scope
900 .borrow()
901 .nodes
902 .traverse(&root, |p, &PathNode { scope_id, .. }| {
903 if let Some(scope_id) = scope_id
904 && removed.iter().any(|r| is_descendant(p, r))
905 {
906 scope_removal_buffer.push(self.scopes.get(&scope_id).cloned().unwrap());
908 }
909 });
910 for removed in removed {
911 scope.borrow_mut().nodes.remove(&removed);
912 }
913 }
914
915 let mut scope_removal_queue = VecDeque::new();
916
917 while let Some(scope_rc) = scope_removal_buffer.pop() {
918 scope_removal_queue.push_front(scope_rc.clone());
921
922 let scope = scope_rc.borrow_mut();
923
924 let mut scope_root_node_id = None;
925
926 scope
928 .nodes
929 .traverse(&[], |path, &PathNode { scope_id, node_id }| {
930 if let Some(scope_id) = scope_id {
931 scope_removal_buffer.push(self.scopes.get(&scope_id).cloned().unwrap());
932 } else {
933 self.node_to_scope.remove(&node_id).unwrap();
934 }
935 if path == [0] {
936 scope_root_node_id = Some(node_id);
937 }
938 });
939
940 mutations.removed.push(MutationRemove::Scope {
943 id: scope_root_node_id.unwrap(),
944 });
945 }
946
947 for scope_rc in scope_removal_queue {
949 let scope = scope_rc.borrow_mut();
950
951 self.scopes.remove(&scope.id);
952
953 CurrentContext::run_with_reactive(
955 CurrentContext {
956 scope_id: scope.id,
957 scopes_storages: self.scopes_storages.clone(),
958 tasks: self.tasks.clone(),
959 task_id_counter: self.task_id_counter.clone(),
960 sender: self.sender.clone(),
961 },
962 || {
963 let _scope = self.scopes_storages.borrow_mut().remove(&scope.id);
965 },
966 );
967
968 self.tasks
970 .borrow_mut()
971 .retain(|_task_id, task| task.borrow().scope_id != scope.id);
972 }
973
974 for added in diff
994 .added
995 .iter()
996 .sorted_by(|a, b| {
997 for (x, y) in a.iter().zip(b.iter()) {
998 match x.cmp(y) {
999 Ordering::Equal => continue,
1000 non_eq => return non_eq.reverse(),
1001 }
1002 }
1003 b.len().cmp(&a.len())
1004 })
1005 .rev()
1006 {
1007 let (parent_node_id, index_inside_parent) = if added.as_ref() == [0] {
1008 let mut index_inside_parent = 0;
1013
1014 let parent_id = scope.borrow().parent_id;
1015 let scope_id = scope.borrow().id;
1016 let parent_node_id = scope.borrow().parent_node_id_in_parent;
1017
1018 if let Some(parent_id) = parent_id {
1019 let mut buffer = Some((parent_id, parent_node_id, scope_id));
1020 while let Some((parent_id, parent_node_id, scope_id)) = buffer.take() {
1021 let parent_scope = self.scopes.get(&parent_id).unwrap();
1022 let parent_scope = parent_scope.borrow();
1023
1024 let scope = self.scopes.get(&scope_id).unwrap();
1025 let scope = scope.borrow();
1026
1027 let path_node_parent = parent_scope.nodes.find(|v| {
1028 if let Some(v) = v {
1029 v.node_id == parent_node_id
1030 } else {
1031 false
1032 }
1033 });
1034
1035 if let Some(path_node_parent) = path_node_parent {
1036 if let Some(scope_id) = path_node_parent.scope_id {
1037 if let Some(parent_id) = parent_scope.parent_id {
1038 buffer.replace((
1040 parent_id,
1041 parent_scope.parent_node_id_in_parent,
1042 scope_id,
1043 ));
1044 } else {
1045 assert_eq!(scope_id, ScopeId::ROOT);
1046 }
1047 } else {
1048 index_inside_parent = *scope.path_in_parent.last().unwrap();
1050 }
1051 } else if let Some(new_parent_id) = parent_scope.parent_id {
1052 buffer.replace((
1054 new_parent_id,
1055 parent_scope.parent_node_id_in_parent,
1056 parent_id,
1057 ));
1058 }
1059 }
1060 } else {
1061 assert_eq!(scope_id, ScopeId::ROOT);
1062 }
1063
1064 (parent_node_id, index_inside_parent)
1065 } else {
1066 parents_to_resync_scopes.insert(Box::from(&added[..added.len() - 1]));
1068 (
1069 scope
1070 .borrow()
1071 .nodes
1072 .get(&added[..added.len() - 1])
1073 .unwrap()
1074 .node_id,
1075 added[added.len() - 1],
1076 )
1077 };
1078
1079 self.node_id_counter += 1;
1080
1081 path_element.with_element(added, |element| match element {
1082 PathElement::Component { .. } => {
1083 self.scope_id_counter += 1;
1084 let scope_id = self.scope_id_counter;
1085
1086 scope.borrow_mut().nodes.insert(
1087 added,
1088 PathNode {
1089 node_id: self.node_id_counter,
1090 scope_id: Some(scope_id),
1091 },
1092 );
1093 }
1094 PathElement::Element { element, .. } => {
1095 mutations.added.push((
1096 self.node_id_counter,
1097 parent_node_id,
1098 index_inside_parent,
1099 element.clone(),
1100 ));
1101
1102 self.node_to_scope
1103 .insert(self.node_id_counter, scope.borrow().id);
1104 scope.borrow_mut().nodes.insert(
1105 added,
1106 PathNode {
1107 node_id: self.node_id_counter,
1108 scope_id: None,
1109 },
1110 );
1111 }
1112 });
1113 }
1114
1115 for (parent, movements) in diff.moved.into_iter().sorted_by(|(a, _), (b, _)| {
1116 for (x, y) in a.iter().zip(b.iter()) {
1117 match x.cmp(y) {
1118 Ordering::Equal => continue,
1119 non_eq => return non_eq.reverse(),
1120 }
1121 }
1122 b.len().cmp(&a.len())
1123 }) {
1124 parents_to_resync_scopes.insert(parent.clone());
1125
1126 let (parent_node_id, paths) = moved_nodes.get_mut(&parent).unwrap();
1127
1128 for (from, to) in movements.into_iter().sorted_by_key(|e| e.0).rev() {
1129 let path_node = paths.remove(&from).unwrap();
1130
1131 let PathNode { node_id, scope_id } = path_node;
1132
1133 let from_path = scope
1135 .borrow()
1136 .nodes
1137 .find_child_path(&parent, |v| v == Some(&path_node))
1138 .unwrap();
1139
1140 let mut to_path = parent.to_vec();
1141 to_path.push(to);
1142
1143 if from_path == to_path {
1144 continue;
1145 }
1146
1147 let path_entry = scope.borrow_mut().nodes.remove(&from_path).unwrap();
1149 scope.borrow_mut().nodes.insert_entry(&to_path, path_entry);
1150
1151 if let Some(scope_id) = scope_id {
1152 let scope_rc = self.scopes.get(&scope_id).cloned().unwrap();
1153
1154 let scope = scope_rc.borrow();
1155
1156 let scope_root_node_id = scope.nodes.get(&[0]).map(|node| node.node_id);
1157
1158 mutations
1160 .moved
1161 .entry(scope.parent_node_id_in_parent)
1162 .or_default()
1163 .push((to, scope_root_node_id.unwrap()));
1164 } else {
1165 mutations
1167 .moved
1168 .entry(*parent_node_id)
1169 .or_default()
1170 .push((to, node_id));
1171 }
1172 }
1173 }
1174
1175 for (modified, flags) in diff.modified {
1176 path_element.with_element(&modified, |element| match element {
1177 PathElement::Component { .. } => {
1178 unreachable!()
1180 }
1181 PathElement::Element { element, .. } => {
1182 let node_id = scope
1183 .borrow()
1184 .nodes
1185 .get(&modified)
1186 .map(|path_node| path_node.node_id)
1187 .unwrap();
1188 mutations.modified.push((node_id, element.clone(), flags));
1189 }
1190 });
1191 }
1192
1193 for parent in parents_to_resync_scopes {
1196 if diff.added.contains(&parent) {
1199 continue;
1201 }
1202
1203 scope
1205 .borrow_mut()
1206 .nodes
1207 .traverse_1_level(&parent, |p, path_node| {
1208 if let Some(scope_id) = path_node.scope_id
1209 && let Some(scope_rc) = self.scopes.get(&scope_id)
1210 {
1211 let mut scope = scope_rc.borrow_mut();
1212 scope.path_in_parent = Box::from(p);
1213 }
1214 });
1215 }
1216 }
1217}
1218
1219#[derive(Default, Debug)]
1220pub struct Diff {
1221 pub added: Vec<Box<[u32]>>,
1222
1223 pub modified: Vec<(Box<[u32]>, DiffModifies)>,
1224
1225 pub removed: Vec<Box<[u32]>>,
1226
1227 pub moved: HashMap<Box<[u32]>, Vec<(u32, u32)>>,
1228}
1229
1230fn is_descendant(candidate: &[u32], ancestor: &[u32]) -> bool {
1231 if ancestor.len() > candidate.len() {
1232 return false;
1233 }
1234 candidate[..ancestor.len()] == *ancestor
1235}