diff.rs 42 KB

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