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