diff.rs 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
  1. /// Diff the `old` node with the `new` node. Emits instructions to modify a
  2. /// physical DOM node that reflects `old` into something that reflects `new`.
  3. ///
  4. /// Upon entry to this function, the physical DOM node must be on the top of the
  5. /// change list stack:
  6. ///
  7. /// [... node]
  8. ///
  9. /// The change list stack is in the same state when this function exits.
  10. ///
  11. /// ----
  12. ///
  13. /// There are more ways of increasing diff performance here that are currently not implemented.
  14. /// Additionally, the caching mechanism has also been tweaked.
  15. ///
  16. /// Instead of having "cached" nodes, each component is, by default, a cached node. This leads to increased
  17. /// memory overhead for large numbers of small components, but we can optimize this by tracking alloc size over time
  18. /// and shrinking bumps down if possible.
  19. ///
  20. /// Additionally, clean up of these components is not done at diff time (though it should), but rather, the diffing
  21. /// proprogates removal lifecycle events for affected components into the event queue. It's not imperative that these
  22. /// are ran immediately, but it should be noted that cleanup of components might be able to emit changes.
  23. ///
  24. /// This diffing only ever occurs on a component-by-component basis (not entire trees at once).
  25. ///
  26. /// Currently, the listener situation is a bit broken.
  27. /// We aren't removing listeners (choosing to leak them instead) :(
  28. /// Eventually, we'll set things up so add/remove listener is an instruction again
  29. ///
  30. /// A major assumption of this diff algorithm when combined with the ChangeList is that the Changelist will be
  31. /// fresh and the event queue is clean. This lets us continue to batch edits together under the same ChangeList
  32. ///
  33. /// More info on how to improve this diffing algorithm:
  34. /// - https://hacks.mozilla.org/2019/03/fast-bump-allocated-virtual-doms-with-rust-and-wasm/
  35. use fxhash::{FxHashMap, FxHashSet};
  36. use generational_arena::Index;
  37. use crate::{
  38. changelist::EditList,
  39. innerlude::{Attribute, Listener, Scope, VElement, VNode, VText},
  40. virtual_dom::LifecycleEvent,
  41. };
  42. use std::cmp::Ordering;
  43. /// The DiffState is a cursor internal to the VirtualDOM's diffing algorithm that allows persistence of state while
  44. /// diffing trees of components. This means we can "re-enter" a subtree of a component by queuing a "NeedToDiff" event.
  45. ///
  46. /// By re-entering via NodeDiff, we can connect disparate edits together into a single EditList. This batching of edits
  47. /// leads to very fast re-renders (all done in a single animation frame).
  48. ///
  49. /// It also means diffing two trees is only ever complex as diffing a single smaller tree, and then re-entering at a
  50. /// different cursor position.
  51. ///
  52. /// The order of these re-entrances is stored in the DiffState itself. The DiffState comes pre-loaded with a set of components
  53. /// that were modified by the eventtrigger. This prevents doubly evaluating components if they wereboth updated via
  54. /// subscriptions and props changes.
  55. struct DiffingMachine<'a> {
  56. change_list: &'a mut EditList<'a>,
  57. queue: FxHashMap<Index, NeedToDiff>,
  58. }
  59. enum NeedToDiff {
  60. PropsChanged,
  61. Subscription,
  62. }
  63. impl<'a> DiffingMachine<'a> {
  64. fn diff_node(&mut self, old: &VNode<'a>, new: &VNode<'a>) {
  65. /*
  66. For each valid case, we "commit traversal", meaning we save this current position in the tree.
  67. Then, we diff and queue an edit event (via chagelist). s single trees - when components show up, we save that traversal and then re-enter later.
  68. When re-entering, we reuse the EditList in DiffState
  69. */
  70. match (old, new) {
  71. // This case occurs when two text nodes are generation
  72. (VNode::Text(VText { text: old_text }), VNode::Text(VText { text: new_text })) => {
  73. if old_text != new_text {
  74. self.change_list.commit_traversal();
  75. self.change_list.set_text(new_text);
  76. }
  77. }
  78. // Definitely different, need to commit update
  79. (VNode::Text(_), VNode::Element(_)) => {
  80. // TODO: Hook up the events properly
  81. // todo!("Hook up events registry");
  82. self.change_list.commit_traversal();
  83. // diff_support::create(cached_set, self.change_list, registry, new, cached_roots);
  84. self.create(new);
  85. // registry.remove_subtree(&old);
  86. self.change_list.replace_with();
  87. }
  88. // Definitely different, need to commit update
  89. (VNode::Element(_), VNode::Text(_)) => {
  90. self.change_list.commit_traversal();
  91. self.create(new);
  92. // create(cached_set, self.change_list, registry, new, cached_roots);
  93. // Note: text nodes cannot have event listeners, so we don't need to
  94. // remove the old node's listeners from our registry her.
  95. self.change_list.replace_with();
  96. }
  97. // compare elements
  98. // if different, schedule different types of update
  99. (VNode::Element(eold), VNode::Element(enew)) => {
  100. // If the element type is completely different, the element needs to be re-rendered completely
  101. if enew.tag_name != eold.tag_name || enew.namespace != eold.namespace {
  102. self.change_list.commit_traversal();
  103. // create(cached_set, self.change_list, registry, new, cached_roots);
  104. // registry.remove_subtree(&old);
  105. self.change_list.replace_with();
  106. return;
  107. }
  108. self.diff_listeners(eold.listeners, enew.listeners);
  109. self.diff_attr(eold.attributes, enew.attributes, enew.namespace.is_some());
  110. self.diff_children(eold.children, enew.children);
  111. }
  112. // No immediate change to dom. If props changed though, queue a "props changed" update
  113. // However, mark these for a
  114. (VNode::Component(_), VNode::Component(_)) => {
  115. todo!("Usage of component VNode not currently supported");
  116. // // Both the new and old nodes are cached.
  117. // (&NodeKind::Cached(ref new), &NodeKind::Cached(ref old)) => {
  118. // cached_roots.insert(new.id);
  119. // if new.id == old.id {
  120. // // This is the same cached node, so nothing has changed!
  121. // return;
  122. // }
  123. // let (new, new_template) = cached_set.get(new.id);
  124. // let (old, old_template) = cached_set.get(old.id);
  125. // if new_template == old_template {
  126. // // If they are both using the same template, then just diff the
  127. // // subtrees.
  128. // diff(cached_set, change_list, registry, old, new, cached_roots);
  129. // } else {
  130. // // Otherwise, they are probably different enough that
  131. // // re-constructing the subtree from scratch should be faster.
  132. // // This doubly holds true if we have a new template.
  133. // change_list.commit_traversal();
  134. // create_and_replace(
  135. // cached_set,
  136. // change_list,
  137. // registry,
  138. // new_template,
  139. // old,
  140. // new,
  141. // cached_roots,
  142. // );
  143. // }
  144. // }
  145. // queue a lifecycle event.
  146. // no change
  147. }
  148. // A component has been birthed!
  149. // Queue its arrival
  150. (_, VNode::Component(_)) => {
  151. todo!("Usage of component VNode not currently supported");
  152. // // Old cached node and new non-cached node. Again, assume that they are
  153. // // probably pretty different and create the new non-cached node afresh.
  154. // (_, &NodeKind::Cached(_)) => {
  155. // change_list.commit_traversal();
  156. // create(cached_set, change_list, registry, new, cached_roots);
  157. // registry.remove_subtree(&old);
  158. // change_list.replace_with();
  159. // }
  160. // }
  161. }
  162. // A component was removed :(
  163. // Queue its removal
  164. (VNode::Component(_), _) => {
  165. // // New cached node when the old node was not cached. In this scenario,
  166. // // we assume that they are pretty different, and it isn't worth diffing
  167. // // the subtrees, so we just create the new cached node afresh.
  168. // (&NodeKind::Cached(ref c), _) => {
  169. // change_list.commit_traversal();
  170. // cached_roots.insert(c.id);
  171. // let (new, new_template) = cached_set.get(c.id);
  172. // create_and_replace(
  173. // cached_set,
  174. // change_list,
  175. // registry,
  176. // new_template,
  177. // old,
  178. // new,
  179. // cached_roots,
  180. // );
  181. // }
  182. todo!("Usage of component VNode not currently supported");
  183. }
  184. // A suspended component appeared!
  185. // Don't do much, just wait
  186. (VNode::Suspended, _) | (_, VNode::Suspended) => {
  187. // (VNode::Element(_), VNode::Suspended) => {}
  188. // (VNode::Text(_), VNode::Suspended) => {}
  189. // (VNode::Component(_), VNode::Suspended) => {}
  190. // (VNode::Suspended, VNode::Element(_)) => {}
  191. // (VNode::Suspended, VNode::Text(_)) => {}
  192. // (VNode::Suspended, VNode::Suspended) => {}
  193. // (VNode::Suspended, VNode::Component(_)) => {}
  194. todo!("Suspended components not currently available")
  195. }
  196. }
  197. }
  198. // Diff event listeners between `old` and `new`.
  199. //
  200. // The listeners' node must be on top of the change list stack:
  201. //
  202. // [... node]
  203. //
  204. // The change list stack is left unchanged.
  205. fn diff_listeners(&mut self, old: &[Listener<'a>], new: &[Listener<'a>]) {
  206. if !old.is_empty() || !new.is_empty() {
  207. self.change_list.commit_traversal();
  208. }
  209. 'outer1: for new_l in new {
  210. unsafe {
  211. // Safety relies on removing `new_l` from the registry manually at
  212. // the end of its lifetime. This happens below in the `'outer2`
  213. // loop, and elsewhere in diffing when removing old dom trees.
  214. // registry.add(new_l);
  215. }
  216. for old_l in old {
  217. if new_l.event == old_l.event {
  218. self.change_list.update_event_listener(new_l);
  219. continue 'outer1;
  220. }
  221. }
  222. self.change_list.new_event_listener(new_l);
  223. }
  224. 'outer2: for old_l in old {
  225. // registry.remove(old_l);
  226. for new_l in new {
  227. if new_l.event == old_l.event {
  228. continue 'outer2;
  229. }
  230. }
  231. self.change_list.remove_event_listener(old_l.event);
  232. }
  233. }
  234. // Diff a node's attributes.
  235. //
  236. // The attributes' node must be on top of the change list stack:
  237. //
  238. // [... node]
  239. //
  240. // The change list stack is left unchanged.
  241. fn diff_attr(
  242. &mut self,
  243. old: &'a [Attribute<'a>],
  244. new: &'a [Attribute<'a>],
  245. is_namespaced: bool,
  246. ) {
  247. // Do O(n^2) passes to add/update and remove attributes, since
  248. // there are almost always very few attributes.
  249. 'outer: for new_attr in new {
  250. if new_attr.is_volatile() {
  251. self.change_list.commit_traversal();
  252. self.change_list
  253. .set_attribute(new_attr.name, new_attr.value, is_namespaced);
  254. } else {
  255. for old_attr in old {
  256. if old_attr.name == new_attr.name {
  257. if old_attr.value != new_attr.value {
  258. self.change_list.commit_traversal();
  259. self.change_list.set_attribute(
  260. new_attr.name,
  261. new_attr.value,
  262. is_namespaced,
  263. );
  264. }
  265. continue 'outer;
  266. }
  267. }
  268. self.change_list.commit_traversal();
  269. self.change_list
  270. .set_attribute(new_attr.name, new_attr.value, is_namespaced);
  271. }
  272. }
  273. 'outer2: for old_attr in old {
  274. for new_attr in new {
  275. if old_attr.name == new_attr.name {
  276. continue 'outer2;
  277. }
  278. }
  279. self.change_list.commit_traversal();
  280. self.change_list.remove_attribute(old_attr.name);
  281. }
  282. }
  283. // Diff the given set of old and new children.
  284. //
  285. // The parent must be on top of the change list stack when this function is
  286. // entered:
  287. //
  288. // [... parent]
  289. //
  290. // the change list stack is in the same state when this function returns.
  291. fn diff_children(&mut self, old: &'a [VNode<'a>], new: &'a [VNode<'a>]) {
  292. if new.is_empty() {
  293. if !old.is_empty() {
  294. self.change_list.commit_traversal();
  295. self.remove_all_children(old);
  296. }
  297. return;
  298. }
  299. if new.len() == 1 {
  300. match (old.first(), &new[0]) {
  301. (
  302. Some(&VNode::Text(VText { text: old_text })),
  303. &VNode::Text(VText { text: new_text }),
  304. ) if old_text == new_text => {
  305. // Don't take this fast path...
  306. }
  307. (_, &VNode::Text(VText { text })) => {
  308. self.change_list.commit_traversal();
  309. self.change_list.set_text(text);
  310. // for o in old {
  311. // registry.remove_subtree(o);
  312. // }
  313. return;
  314. }
  315. (_, _) => {}
  316. }
  317. }
  318. if old.is_empty() {
  319. if !new.is_empty() {
  320. self.change_list.commit_traversal();
  321. self.create_and_append_children(new);
  322. }
  323. return;
  324. }
  325. let new_is_keyed = new[0].key().is_some();
  326. let old_is_keyed = old[0].key().is_some();
  327. debug_assert!(
  328. new.iter().all(|n| n.key().is_some() == new_is_keyed),
  329. "all siblings must be keyed or all siblings must be non-keyed"
  330. );
  331. debug_assert!(
  332. old.iter().all(|o| o.key().is_some() == old_is_keyed),
  333. "all siblings must be keyed or all siblings must be non-keyed"
  334. );
  335. if new_is_keyed && old_is_keyed {
  336. let t = self.change_list.next_temporary();
  337. // diff_keyed_children(self.change_list, old, new);
  338. // diff_keyed_children(self.change_list, old, new, cached_roots);
  339. // diff_keyed_children(cached_set, self.change_list, registry, old, new, cached_roots);
  340. self.change_list.set_next_temporary(t);
  341. } else {
  342. self.diff_non_keyed_children(old, new);
  343. // diff_non_keyed_children(cached_set, change_list, registry, old, new, cached_roots);
  344. }
  345. }
  346. // Diffing "keyed" children.
  347. //
  348. // With keyed children, we care about whether we delete, move, or create nodes
  349. // versus mutate existing nodes in place. Presumably there is some sort of CSS
  350. // transition animation that makes the virtual DOM diffing algorithm
  351. // observable. By specifying keys for nodes, we know which virtual DOM nodes
  352. // must reuse (or not reuse) the same physical DOM nodes.
  353. //
  354. // This is loosely based on Inferno's keyed patching implementation. However, we
  355. // have to modify the algorithm since we are compiling the diff down into change
  356. // list instructions that will be executed later, rather than applying the
  357. // changes to the DOM directly as we compare virtual DOMs.
  358. //
  359. // https://github.com/infernojs/inferno/blob/36fd96/packages/inferno/src/DOM/patching.ts#L530-L739
  360. //
  361. // When entering this function, the parent must be on top of the change list
  362. // stack:
  363. //
  364. // [... parent]
  365. //
  366. // Upon exiting, the change list stack is in the same state.
  367. fn diff_keyed_children(&mut self, old: &[VNode<'a>], new: &[VNode<'a>]) {
  368. // let DiffState { change_list, queue } = &*state;
  369. if cfg!(debug_assertions) {
  370. let mut keys = fxhash::FxHashSet::default();
  371. let mut assert_unique_keys = |children: &[VNode]| {
  372. keys.clear();
  373. for child in children {
  374. let key = child.key();
  375. debug_assert!(
  376. key.is_some(),
  377. "if any sibling is keyed, all siblings must be keyed"
  378. );
  379. keys.insert(key);
  380. }
  381. debug_assert_eq!(
  382. children.len(),
  383. keys.len(),
  384. "keyed siblings must each have a unique key"
  385. );
  386. };
  387. assert_unique_keys(old);
  388. assert_unique_keys(new);
  389. }
  390. // First up, we diff all the nodes with the same key at the beginning of the
  391. // children.
  392. //
  393. // `shared_prefix_count` is the count of how many nodes at the start of
  394. // `new` and `old` share the same keys.
  395. let shared_prefix_count = match self.diff_keyed_prefix(old, new) {
  396. KeyedPrefixResult::Finished => return,
  397. KeyedPrefixResult::MoreWorkToDo(count) => count,
  398. };
  399. match self.diff_keyed_prefix(old, new) {
  400. KeyedPrefixResult::Finished => return,
  401. KeyedPrefixResult::MoreWorkToDo(count) => count,
  402. };
  403. // Next, we find out how many of the nodes at the end of the children have
  404. // the same key. We do _not_ diff them yet, since we want to emit the change
  405. // list instructions such that they can be applied in a single pass over the
  406. // DOM. Instead, we just save this information for later.
  407. //
  408. // `shared_suffix_count` is the count of how many nodes at the end of `new`
  409. // and `old` share the same keys.
  410. let shared_suffix_count = old[shared_prefix_count..]
  411. .iter()
  412. .rev()
  413. .zip(new[shared_prefix_count..].iter().rev())
  414. .take_while(|&(old, new)| old.key() == new.key())
  415. .count();
  416. let old_shared_suffix_start = old.len() - shared_suffix_count;
  417. let new_shared_suffix_start = new.len() - shared_suffix_count;
  418. // Ok, we now hopefully have a smaller range of children in the middle
  419. // within which to re-order nodes with the same keys, remove old nodes with
  420. // now-unused keys, and create new nodes with fresh keys.
  421. self.diff_keyed_middle(
  422. &old[shared_prefix_count..old_shared_suffix_start],
  423. &new[shared_prefix_count..new_shared_suffix_start],
  424. shared_prefix_count,
  425. shared_suffix_count,
  426. old_shared_suffix_start,
  427. );
  428. // Finally, diff the nodes at the end of `old` and `new` that share keys.
  429. let old_suffix = &old[old_shared_suffix_start..];
  430. let new_suffix = &new[new_shared_suffix_start..];
  431. debug_assert_eq!(old_suffix.len(), new_suffix.len());
  432. if !old_suffix.is_empty() {
  433. self.diff_keyed_suffix(old_suffix, new_suffix, new_shared_suffix_start)
  434. }
  435. }
  436. // Diff the prefix of children in `new` and `old` that share the same keys in
  437. // the same order.
  438. //
  439. // Upon entry of this function, the change list stack must be:
  440. //
  441. // [... parent]
  442. //
  443. // Upon exit, the change list stack is the same.
  444. fn diff_keyed_prefix(&mut self, old: &[VNode<'a>], new: &[VNode<'a>]) -> KeyedPrefixResult {
  445. self.change_list.go_down();
  446. let mut shared_prefix_count = 0;
  447. for (i, (old, new)) in old.iter().zip(new.iter()).enumerate() {
  448. if old.key() != new.key() {
  449. break;
  450. }
  451. self.change_list.go_to_sibling(i);
  452. self.diff_node(old, new);
  453. shared_prefix_count += 1;
  454. }
  455. // If that was all of the old children, then create and append the remaining
  456. // new children and we're finished.
  457. if shared_prefix_count == old.len() {
  458. self.change_list.go_up();
  459. self.change_list.commit_traversal();
  460. self.create_and_append_children(&new[shared_prefix_count..]);
  461. return KeyedPrefixResult::Finished;
  462. }
  463. // And if that was all of the new children, then remove all of the remaining
  464. // old children and we're finished.
  465. if shared_prefix_count == new.len() {
  466. self.change_list.go_to_sibling(shared_prefix_count);
  467. self.change_list.commit_traversal();
  468. self.remove_self_and_next_siblings(&old[shared_prefix_count..]);
  469. return KeyedPrefixResult::Finished;
  470. }
  471. self.change_list.go_up();
  472. KeyedPrefixResult::MoreWorkToDo(shared_prefix_count)
  473. }
  474. // The most-general, expensive code path for keyed children diffing.
  475. //
  476. // We find the longest subsequence within `old` of children that are relatively
  477. // ordered the same way in `new` (via finding a longest-increasing-subsequence
  478. // of the old child's index within `new`). The children that are elements of
  479. // this subsequence will remain in place, minimizing the number of DOM moves we
  480. // will have to do.
  481. //
  482. // Upon entry to this function, the change list stack must be:
  483. //
  484. // [... parent]
  485. //
  486. // Upon exit from this function, it will be restored to that same state.
  487. fn diff_keyed_middle(
  488. &mut self,
  489. old: &[VNode<'a>],
  490. mut new: &[VNode<'a>],
  491. shared_prefix_count: usize,
  492. shared_suffix_count: usize,
  493. old_shared_suffix_start: usize,
  494. ) {
  495. // Should have already diffed the shared-key prefixes and suffixes.
  496. debug_assert_ne!(new.first().map(|n| n.key()), old.first().map(|o| o.key()));
  497. debug_assert_ne!(new.last().map(|n| n.key()), old.last().map(|o| o.key()));
  498. // The algorithm below relies upon using `u32::MAX` as a sentinel
  499. // value, so if we have that many new nodes, it won't work. This
  500. // check is a bit academic (hence only enabled in debug), since
  501. // wasm32 doesn't have enough address space to hold that many nodes
  502. // in memory.
  503. debug_assert!(new.len() < u32::MAX as usize);
  504. // Map from each `old` node's key to its index within `old`.
  505. let mut old_key_to_old_index = FxHashMap::default();
  506. old_key_to_old_index.reserve(old.len());
  507. old_key_to_old_index.extend(old.iter().enumerate().map(|(i, o)| (o.key(), i)));
  508. // The set of shared keys between `new` and `old`.
  509. let mut shared_keys = FxHashSet::default();
  510. // Map from each index in `new` to the index of the node in `old` that
  511. // has the same key.
  512. let mut new_index_to_old_index = Vec::with_capacity(new.len());
  513. new_index_to_old_index.extend(new.iter().map(|n| {
  514. let key = n.key();
  515. if let Some(&i) = old_key_to_old_index.get(&key) {
  516. shared_keys.insert(key);
  517. i
  518. } else {
  519. u32::MAX as usize
  520. }
  521. }));
  522. // If none of the old keys are reused by the new children, then we
  523. // remove all the remaining old children and create the new children
  524. // afresh.
  525. if shared_suffix_count == 0 && shared_keys.is_empty() {
  526. if shared_prefix_count == 0 {
  527. self.change_list.commit_traversal();
  528. self.remove_all_children(old);
  529. } else {
  530. self.change_list.go_down_to_child(shared_prefix_count);
  531. self.change_list.commit_traversal();
  532. self.remove_self_and_next_siblings(&old[shared_prefix_count..]);
  533. }
  534. self.create_and_append_children(new);
  535. return;
  536. }
  537. // Save each of the old children whose keys are reused in the new
  538. // children.
  539. let mut old_index_to_temp = vec![u32::MAX; old.len()];
  540. let mut start = 0;
  541. loop {
  542. let end = (start..old.len())
  543. .find(|&i| {
  544. let key = old[i].key();
  545. !shared_keys.contains(&key)
  546. })
  547. .unwrap_or(old.len());
  548. if end - start > 0 {
  549. self.change_list.commit_traversal();
  550. let mut t = self.change_list.save_children_to_temporaries(
  551. shared_prefix_count + start,
  552. shared_prefix_count + end,
  553. );
  554. for i in start..end {
  555. old_index_to_temp[i] = t;
  556. t += 1;
  557. }
  558. }
  559. debug_assert!(end <= old.len());
  560. if end == old.len() {
  561. break;
  562. } else {
  563. start = end + 1;
  564. }
  565. }
  566. // Remove any old children whose keys were not reused in the new
  567. // children. Remove from the end first so that we don't mess up indices.
  568. let mut removed_count = 0;
  569. for (i, old_child) in old.iter().enumerate().rev() {
  570. if !shared_keys.contains(&old_child.key()) {
  571. // registry.remove_subtree(old_child);
  572. // todo
  573. self.change_list.commit_traversal();
  574. self.change_list.remove_child(i + shared_prefix_count);
  575. removed_count += 1;
  576. }
  577. }
  578. // If there aren't any more new children, then we are done!
  579. if new.is_empty() {
  580. return;
  581. }
  582. // The longest increasing subsequence within `new_index_to_old_index`. This
  583. // is the longest sequence on DOM nodes in `old` that are relatively ordered
  584. // correctly within `new`. We will leave these nodes in place in the DOM,
  585. // and only move nodes that are not part of the LIS. This results in the
  586. // maximum number of DOM nodes left in place, AKA the minimum number of DOM
  587. // nodes moved.
  588. let mut new_index_is_in_lis = FxHashSet::default();
  589. new_index_is_in_lis.reserve(new_index_to_old_index.len());
  590. let mut predecessors = vec![0; new_index_to_old_index.len()];
  591. let mut starts = vec![0; new_index_to_old_index.len()];
  592. longest_increasing_subsequence::lis_with(
  593. &new_index_to_old_index,
  594. &mut new_index_is_in_lis,
  595. |a, b| a < b,
  596. &mut predecessors,
  597. &mut starts,
  598. );
  599. // Now we will iterate from the end of the new children back to the
  600. // beginning, diffing old children we are reusing and if they aren't in the
  601. // LIS moving them to their new destination, or creating new children. Note
  602. // that iterating in reverse order lets us use `Node.prototype.insertBefore`
  603. // to move/insert children.
  604. //
  605. // But first, we ensure that we have a child on the change list stack that
  606. // we can `insertBefore`. We handle this once before looping over `new`
  607. // children, so that we don't have to keep checking on every loop iteration.
  608. if shared_suffix_count > 0 {
  609. // There is a shared suffix after these middle children. We will be
  610. // inserting before that shared suffix, so add the first child of that
  611. // shared suffix to the change list stack.
  612. //
  613. // [... parent]
  614. self.change_list
  615. .go_down_to_child(old_shared_suffix_start - removed_count);
  616. // [... parent first_child_of_shared_suffix]
  617. } else {
  618. // There is no shared suffix coming after these middle children.
  619. // Therefore we have to process the last child in `new` and move it to
  620. // the end of the parent's children if it isn't already there.
  621. let last_index = new.len() - 1;
  622. // uhhhh why an unwrap?
  623. let last = new.last().unwrap();
  624. // let last = new.last().unwrap_throw();
  625. new = &new[..new.len() - 1];
  626. if shared_keys.contains(&last.key()) {
  627. let old_index = new_index_to_old_index[last_index];
  628. let temp = old_index_to_temp[old_index];
  629. // [... parent]
  630. self.change_list.go_down_to_temp_child(temp);
  631. // [... parent last]
  632. self.diff_node(&old[old_index], last);
  633. if new_index_is_in_lis.contains(&last_index) {
  634. // Don't move it, since it is already where it needs to be.
  635. } else {
  636. self.change_list.commit_traversal();
  637. // [... parent last]
  638. self.change_list.append_child();
  639. // [... parent]
  640. self.change_list.go_down_to_temp_child(temp);
  641. // [... parent last]
  642. }
  643. } else {
  644. self.change_list.commit_traversal();
  645. // [... parent]
  646. self.create(last);
  647. // [... parent last]
  648. self.change_list.append_child();
  649. // [... parent]
  650. self.change_list.go_down_to_reverse_child(0);
  651. // [... parent last]
  652. }
  653. }
  654. for (new_index, new_child) in new.iter().enumerate().rev() {
  655. let old_index = new_index_to_old_index[new_index];
  656. if old_index == u32::MAX as usize {
  657. debug_assert!(!shared_keys.contains(&new_child.key()));
  658. self.change_list.commit_traversal();
  659. // [... parent successor]
  660. self.create(new_child);
  661. // [... parent successor new_child]
  662. self.change_list.insert_before();
  663. // [... parent new_child]
  664. } else {
  665. debug_assert!(shared_keys.contains(&new_child.key()));
  666. let temp = old_index_to_temp[old_index];
  667. debug_assert_ne!(temp, u32::MAX);
  668. if new_index_is_in_lis.contains(&new_index) {
  669. // [... parent successor]
  670. self.change_list.go_to_temp_sibling(temp);
  671. // [... parent new_child]
  672. } else {
  673. self.change_list.commit_traversal();
  674. // [... parent successor]
  675. self.change_list.push_temporary(temp);
  676. // [... parent successor new_child]
  677. self.change_list.insert_before();
  678. // [... parent new_child]
  679. }
  680. self.diff_node(&old[old_index], new_child);
  681. }
  682. }
  683. // [... parent child]
  684. self.change_list.go_up();
  685. // [... parent]
  686. }
  687. // Diff the suffix of keyed children that share the same keys in the same order.
  688. //
  689. // The parent must be on the change list stack when we enter this function:
  690. //
  691. // [... parent]
  692. //
  693. // When this function exits, the change list stack remains the same.
  694. fn diff_keyed_suffix(
  695. &mut self,
  696. old: &[VNode<'a>],
  697. new: &[VNode<'a>],
  698. new_shared_suffix_start: usize,
  699. ) {
  700. debug_assert_eq!(old.len(), new.len());
  701. debug_assert!(!old.is_empty());
  702. // [... parent]
  703. self.change_list.go_down();
  704. // [... parent new_child]
  705. for (i, (old_child, new_child)) in old.iter().zip(new.iter()).enumerate() {
  706. self.change_list.go_to_sibling(new_shared_suffix_start + i);
  707. self.diff_node(old_child, new_child);
  708. }
  709. // [... parent]
  710. self.change_list.go_up();
  711. }
  712. // Diff children that are not keyed.
  713. //
  714. // The parent must be on the top of the change list stack when entering this
  715. // function:
  716. //
  717. // [... parent]
  718. //
  719. // the change list stack is in the same state when this function returns.
  720. fn diff_non_keyed_children(&mut self, old: &'a [VNode<'a>], new: &'a [VNode<'a>]) {
  721. // Handled these cases in `diff_children` before calling this function.
  722. debug_assert!(!new.is_empty());
  723. debug_assert!(!old.is_empty());
  724. // [... parent]
  725. self.change_list.go_down();
  726. // [... parent child]
  727. for (i, (new_child, old_child)) in new.iter().zip(old.iter()).enumerate() {
  728. // [... parent prev_child]
  729. self.change_list.go_to_sibling(i);
  730. // [... parent this_child]
  731. self.diff_node(old_child, new_child);
  732. }
  733. match old.len().cmp(&new.len()) {
  734. Ordering::Greater => {
  735. // [... parent prev_child]
  736. self.change_list.go_to_sibling(new.len());
  737. // [... parent first_child_to_remove]
  738. self.change_list.commit_traversal();
  739. // support::remove_self_and_next_siblings(state, &old[new.len()..]);
  740. self.remove_self_and_next_siblings(&old[new.len()..]);
  741. // [... parent]
  742. }
  743. Ordering::Less => {
  744. // [... parent last_child]
  745. self.change_list.go_up();
  746. // [... parent]
  747. self.change_list.commit_traversal();
  748. self.create_and_append_children(&new[old.len()..]);
  749. }
  750. Ordering::Equal => {
  751. // [... parent child]
  752. self.change_list.go_up();
  753. // [... parent]
  754. }
  755. }
  756. }
  757. // ======================
  758. // Support methods
  759. // ======================
  760. // Emit instructions to create the given virtual node.
  761. //
  762. // The change list stack may have any shape upon entering this function:
  763. //
  764. // [...]
  765. //
  766. // When this function returns, the new node is on top of the change list stack:
  767. //
  768. // [... node]
  769. fn create(&mut self, node: &VNode<'a>) {
  770. debug_assert!(self.change_list.traversal_is_committed());
  771. match node {
  772. VNode::Text(VText { text }) => {
  773. self.change_list.create_text_node(text);
  774. }
  775. VNode::Element(&VElement {
  776. key: _,
  777. tag_name,
  778. listeners,
  779. attributes,
  780. children,
  781. namespace,
  782. }) => {
  783. if let Some(namespace) = namespace {
  784. self.change_list.create_element_ns(tag_name, namespace);
  785. } else {
  786. self.change_list.create_element(tag_name);
  787. }
  788. for l in listeners {
  789. // unsafe {
  790. // registry.add(l);
  791. // }
  792. self.change_list.new_event_listener(l);
  793. }
  794. for attr in attributes {
  795. self.change_list
  796. .set_attribute(&attr.name, &attr.value, namespace.is_some());
  797. }
  798. // Fast path: if there is a single text child, it is faster to
  799. // create-and-append the text node all at once via setting the
  800. // parent's `textContent` in a single change list instruction than
  801. // to emit three instructions to (1) create a text node, (2) set its
  802. // text content, and finally (3) append the text node to this
  803. // parent.
  804. if children.len() == 1 {
  805. if let VNode::Text(VText { text }) = children[0] {
  806. self.change_list.set_text(text);
  807. return;
  808. }
  809. }
  810. for child in children {
  811. self.create(child);
  812. self.change_list.append_child();
  813. }
  814. }
  815. /*
  816. todo: integrate re-entrace
  817. */
  818. // NodeKind::Cached(ref c) => {
  819. // cached_roots.insert(c.id);
  820. // let (node, template) = cached_set.get(c.id);
  821. // if let Some(template) = template {
  822. // create_with_template(
  823. // cached_set,
  824. // self.change_list,
  825. // registry,
  826. // template,
  827. // node,
  828. // cached_roots,
  829. // );
  830. // } else {
  831. // create(cached_set, change_list, registry, node, cached_roots);
  832. // }
  833. // }
  834. VNode::Suspended => {
  835. todo!("Creation of VNode::Suspended not yet supported")
  836. }
  837. VNode::Component(_) => {
  838. todo!("Creation of VNode::Component not yet supported")
  839. }
  840. }
  841. }
  842. // Remove all of a node's children.
  843. //
  844. // The change list stack must have this shape upon entry to this function:
  845. //
  846. // [... parent]
  847. //
  848. // When this function returns, the change list stack is in the same state.
  849. pub fn remove_all_children(&mut self, old: &[VNode<'a>]) {
  850. debug_assert!(self.change_list.traversal_is_committed());
  851. for child in old {
  852. // registry.remove_subtree(child);
  853. }
  854. // Fast way to remove all children: set the node's textContent to an empty
  855. // string.
  856. self.change_list.set_text("");
  857. }
  858. // Create the given children and append them to the parent node.
  859. //
  860. // The parent node must currently be on top of the change list stack:
  861. //
  862. // [... parent]
  863. //
  864. // When this function returns, the change list stack is in the same state.
  865. pub fn create_and_append_children(&mut self, new: &[VNode<'a>]) {
  866. debug_assert!(self.change_list.traversal_is_committed());
  867. for child in new {
  868. self.create(child);
  869. self.change_list.append_child();
  870. }
  871. }
  872. // Remove the current child and all of its following siblings.
  873. //
  874. // The change list stack must have this shape upon entry to this function:
  875. //
  876. // [... parent child]
  877. //
  878. // After the function returns, the child is no longer on the change list stack:
  879. //
  880. // [... parent]
  881. pub fn remove_self_and_next_siblings(&mut self, old: &[VNode<'a>]) {
  882. debug_assert!(self.change_list.traversal_is_committed());
  883. for child in old {
  884. // registry.remove_subtree(child);
  885. }
  886. self.change_list.remove_self_and_next_siblings();
  887. }
  888. }
  889. enum KeyedPrefixResult {
  890. // Fast path: we finished diffing all the children just by looking at the
  891. // prefix of shared keys!
  892. Finished,
  893. // There is more diffing work to do. Here is a count of how many children at
  894. // the beginning of `new` and `old` we already processed.
  895. MoreWorkToDo(usize),
  896. }
  897. mod support {
  898. use super::*;
  899. // // Get or create the template.
  900. // //
  901. // // Upon entering this function the change list stack may be in any shape:
  902. // //
  903. // // [...]
  904. // //
  905. // // When this function returns, it leaves a freshly cloned copy of the template
  906. // // on the top of the change list stack:
  907. // //
  908. // // [... template]
  909. // #[inline]
  910. // pub fn get_or_create_template<'a>(// cached_set: &'a CachedSet,
  911. // // change_list: &mut ChangeListBuilder,
  912. // // registry: &mut EventsRegistry,
  913. // // cached_roots: &mut FxHashSet<CacheId>,
  914. // // template_id: CacheId,
  915. // ) -> (&'a Node<'a>, bool) {
  916. // let (template, template_template) = cached_set.get(template_id);
  917. // debug_assert!(
  918. // template_template.is_none(),
  919. // "templates should not be templated themselves"
  920. // );
  921. // // If we haven't already created and saved the physical DOM subtree for this
  922. // // template, do that now.
  923. // if change_list.has_template(template_id) {
  924. // // Clone the template and push it onto the stack.
  925. // //
  926. // // [...]
  927. // change_list.push_template(template_id);
  928. // // [... template]
  929. // (template, true)
  930. // } else {
  931. // // [...]
  932. // create(cached_set, change_list, registry, template, cached_roots);
  933. // // [... template]
  934. // change_list.save_template(template_id);
  935. // // [... template]
  936. // (template, false)
  937. // }
  938. // }
  939. // pub fn create_and_replace(
  940. // cached_set: &CachedSet,
  941. // change_list: &mut ChangeListBuilder,
  942. // registry: &mut EventsRegistry,
  943. // new_template: Option<CacheId>,
  944. // old: &Node,
  945. // new: &Node,
  946. // cached_roots: &mut FxHashSet<CacheId>,
  947. // ) {
  948. // debug_assert!(change_list.traversal_is_committed());
  949. // if let Some(template_id) = new_template {
  950. // let (template, needs_listeners) = get_or_create_template(
  951. // cached_set,
  952. // change_list,
  953. // registry,
  954. // cached_roots,
  955. // template_id,
  956. // );
  957. // change_list.replace_with();
  958. // let mut old_forcing = None;
  959. // if needs_listeners {
  960. // old_forcing = Some(change_list.push_force_new_listeners());
  961. // }
  962. // diff(
  963. // cached_set,
  964. // change_list,
  965. // registry,
  966. // template,
  967. // new,
  968. // cached_roots,
  969. // );
  970. // if let Some(old) = old_forcing {
  971. // change_list.pop_force_new_listeners(old);
  972. // }
  973. // change_list.commit_traversal();
  974. // } else {
  975. // create(cached_set, change_list, registry, new, cached_roots);
  976. // change_list.replace_with();
  977. // }
  978. // registry.remove_subtree(old);
  979. // }
  980. // pub fn create_with_template(
  981. // cached_set: &CachedSet,
  982. // change_list: &mut ChangeListBuilder,
  983. // registry: &mut EventsRegistry,
  984. // template_id: CacheId,
  985. // node: &Node,
  986. // cached_roots: &mut FxHashSet<CacheId>,
  987. // ) {
  988. // debug_assert!(change_list.traversal_is_committed());
  989. // // [...]
  990. // let (template, needs_listeners) =
  991. // get_or_create_template(cached_set, change_list, registry, cached_roots, template_id);
  992. // // [... template]
  993. // // Now diff the node with its template.
  994. // //
  995. // // We must force adding new listeners instead of updating existing ones,
  996. // // since listeners don't get cloned in `cloneNode`.
  997. // let mut old_forcing = None;
  998. // if needs_listeners {
  999. // old_forcing = Some(change_list.push_force_new_listeners());
  1000. // }
  1001. // diff(
  1002. // cached_set,
  1003. // change_list,
  1004. // registry,
  1005. // template,
  1006. // node,
  1007. // cached_roots,
  1008. // );
  1009. // if let Some(old) = old_forcing {
  1010. // change_list.pop_force_new_listeners(old);
  1011. // }
  1012. // // Make sure that we come back up to the level we were at originally.
  1013. // change_list.commit_traversal();
  1014. // }
  1015. }