diff.rs 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451
  1. //! This module contains the stateful DiffMachine and all methods to diff VNodes, their properties, and their children.
  2. //! The DiffMachine calculates the diffs between the old and new frames, updates the new nodes, and modifies the real dom.
  3. //!
  4. //! ## Notice:
  5. //! The inspiration and code for this module was originally taken from Dodrio (@fitzgen) and then modified to support
  6. //! Components, Fragments, Suspense, SubTree memoization, and additional batching operations.
  7. //!
  8. //! ## Implementation Details:
  9. //!
  10. //! ### IDs for elements
  11. //! --------------------
  12. //! All nodes are addressed by their IDs. The RealDom provides an imperative interface for making changes to these nodes.
  13. //! We don't necessarily require that DOM changes happen instnatly during the diffing process, so the implementor may choose
  14. //! to batch nodes if it is more performant for their application. The expectation is that renderers use a Slotmap for nodes
  15. //! whose keys can be converted to u64 on FFI boundaries.
  16. //!
  17. //! When new nodes are created through `render`, they won't know which real node they correspond to. During diffing, we
  18. //! always make sure to copy over the ID. If we don't do this properly, the realdomnode will be populated incorrectly and
  19. //! brick the user's page.
  20. //!
  21. //! ## Subtree Memoization
  22. //! -----------------------
  23. //! We also employ "subtree memoization" which saves us from having to check trees which take no dynamic content. We can
  24. //! detect if a subtree is "static" by checking if its children are "static". Since we dive into the tree depth-first, the
  25. //! calls to "create" propogate this information upwards. Structures like the one below are entirely static:
  26. //! ```rust
  27. //! rsx!( div { class: "hello world", "this node is entirely static" } )
  28. //! ```
  29. //! Because the subtrees won't be diffed, their "real node" data will be stale (invalid), so its up to the reconciler to
  30. //! track nodes created in a scope and clean up all relevant data. Support for this is currently WIP
  31. //!
  32. //! ## Bloom Filter and Heuristics
  33. //! ------------------------------
  34. //! For all components, we employ some basic heuristics to speed up allocations and pre-size bump arenas. The heuristics are
  35. //! currently very rough, but will get better as time goes on. For FFI, we recommend using a bloom filter to cache strings.
  36. //!
  37. //! ## Garbage Collection
  38. //! ---------------------
  39. //! We roughly place the role of garbage collection onto the reconciler. Dioxus needs to manage the lifecycle of components
  40. //! but will not spend any time cleaning up old elements. It's the Reconciler's duty to understand which elements need to
  41. //! be cleaned up *after* the diffing is completed. The reconciler should schedule this garbage collection as the absolute
  42. //! lowest priority task, after all edits have been applied.
  43. //!
  44. //!
  45. //! Further Reading and Thoughts
  46. //! ----------------------------
  47. //! There are more ways of increasing diff performance here that are currently not implemented.
  48. //! More info on how to improve this diffing algorithm:
  49. //! - https://hacks.mozilla.org/2019/03/fast-bump-allocated-virtual-doms-with-rust-and-wasm/
  50. use crate::{arena::SharedArena, innerlude::*, tasks::TaskQueue};
  51. use fxhash::FxHashSet;
  52. use std::any::Any;
  53. /// The accompanying "real dom" exposes an imperative API for controlling the UI layout
  54. ///
  55. /// Instead of having handles directly over nodes, Dioxus uses simple u64s as node IDs.
  56. /// The expectation is that the underlying renderer will mainain their Nodes in something like slotmap or an ECS memory
  57. /// where indexing is very fast. For reference, the slotmap in the WebSys renderer takes about 3ns to randomly access any
  58. /// node.
  59. ///
  60. /// The "RealDom" abstracts over the... real dom. The RealDom trait assumes that the renderer maintains a stack of real
  61. /// nodes as the diffing algorithm descenes through the tree. This means that whatever is on top of the stack will receive
  62. /// any modifications that follow. This technique enables the diffing algorithm to avoid directly handling or storing any
  63. /// target-specific Node type as well as easily serializing the edits to be sent over a network or IPC connection.
  64. pub trait RealDom<'a> {
  65. fn request_available_node(&mut self) -> RealDomNode;
  66. // node ref
  67. fn raw_node_as_any_mut(&self) -> &mut dyn Any;
  68. }
  69. pub struct DomEditor<'real, 'bump> {
  70. edits: &'real mut Vec<DomEdit<'bump>>,
  71. }
  72. use DomEdit::*;
  73. impl<'real, 'bump> DomEditor<'real, 'bump> {
  74. // Navigation
  75. pub(crate) fn push(&mut self, root: RealDomNode) {
  76. self.edits.push(PushRoot { root: root.0 });
  77. }
  78. pub(crate) fn pop(&mut self) {
  79. self.edits.push(PopRoot {});
  80. }
  81. // Add Nodes to the dom
  82. // add m nodes from the stack
  83. pub(crate) fn append_children(&mut self, many: u32) {
  84. self.edits.push(AppendChildren { many });
  85. }
  86. // replace the n-m node on the stack with the m nodes
  87. // ends with the last element of the chain on the top of the stack
  88. pub(crate) fn replace_with(&mut self, many: u32) {
  89. self.edits.push(ReplaceWith { many });
  90. }
  91. // Remove Nodesfrom the dom
  92. pub(crate) fn remove(&mut self) {
  93. self.edits.push(Remove);
  94. }
  95. pub(crate) fn remove_all_children(&mut self) {
  96. self.edits.push(RemoveAllChildren);
  97. }
  98. // Create
  99. pub(crate) fn create_text_node(&mut self, text: &'bump str, id: RealDomNode) {
  100. self.edits.push(CreateTextNode { text, id: id.0 });
  101. }
  102. pub(crate) fn create_element(
  103. &mut self,
  104. tag: &'static str,
  105. ns: Option<&'static str>,
  106. id: RealDomNode,
  107. ) {
  108. match ns {
  109. Some(ns) => self.edits.push(CreateElementNs { id: id.0, ns, tag }),
  110. None => self.edits.push(CreateElement { id: id.0, tag }),
  111. }
  112. }
  113. // placeholders are nodes that don't get rendered but still exist as an "anchor" in the real dom
  114. pub(crate) fn create_placeholder(&mut self, id: RealDomNode) {
  115. self.edits.push(CreatePlaceholder { id: id.0 });
  116. }
  117. // events
  118. pub(crate) fn new_event_listener(
  119. &mut self,
  120. event: &'static str,
  121. scope: ScopeIdx,
  122. element_id: usize,
  123. realnode: RealDomNode,
  124. ) {
  125. self.edits.push(NewEventListener {
  126. scope,
  127. event,
  128. idx: element_id,
  129. node: realnode.0,
  130. });
  131. }
  132. pub(crate) fn remove_event_listener(&mut self, event: &'static str) {
  133. self.edits.push(RemoveEventListener { event });
  134. }
  135. // modify
  136. pub(crate) fn set_text(&mut self, text: &'bump str) {
  137. self.edits.push(SetText { text });
  138. }
  139. pub(crate) fn set_attribute(
  140. &mut self,
  141. field: &'static str,
  142. value: &'bump str,
  143. ns: Option<&'static str>,
  144. ) {
  145. self.edits.push(SetAttribute { field, value, ns });
  146. }
  147. pub(crate) fn remove_attribute(&mut self, name: &'static str) {
  148. self.edits.push(RemoveAttribute { name });
  149. }
  150. }
  151. pub struct DiffMachine<'real, 'bump, Dom: RealDom<'bump>> {
  152. pub dom: &'real mut Dom,
  153. pub edits: DomEditor<'real, 'bump>,
  154. pub components: &'bump SharedArena,
  155. pub task_queue: &'bump TaskQueue,
  156. pub cur_idx: ScopeIdx,
  157. pub diffed: FxHashSet<ScopeIdx>,
  158. pub event_queue: EventQueue,
  159. pub seen_nodes: FxHashSet<ScopeIdx>,
  160. }
  161. impl<'real, 'bump, Dom> DiffMachine<'real, 'bump, Dom>
  162. where
  163. Dom: RealDom<'bump>,
  164. {
  165. pub fn new(
  166. edits: &'real mut Vec<DomEdit<'bump>>,
  167. dom: &'real mut Dom,
  168. components: &'bump SharedArena,
  169. cur_idx: ScopeIdx,
  170. event_queue: EventQueue,
  171. task_queue: &'bump TaskQueue,
  172. ) -> Self {
  173. Self {
  174. edits: DomEditor { edits },
  175. components,
  176. dom,
  177. cur_idx,
  178. event_queue,
  179. task_queue,
  180. diffed: FxHashSet::default(),
  181. seen_nodes: FxHashSet::default(),
  182. }
  183. }
  184. // Diff the `old` node with the `new` node. Emits instructions to modify a
  185. // physical DOM node that reflects `old` into something that reflects `new`.
  186. //
  187. // the real stack should be what it is coming in and out of this function (ideally empty)
  188. //
  189. // each function call assumes the stack is fresh (empty).
  190. pub fn diff_node(&mut self, old_node: &'bump VNode<'bump>, new_node: &'bump VNode<'bump>) {
  191. match (&old_node.kind, &new_node.kind) {
  192. // Handle the "sane" cases first.
  193. // The rsx and html macros strongly discourage dynamic lists not encapsulated by a "Fragment".
  194. // So the sane (and fast!) cases are where the virtual structure stays the same and is easily diffable.
  195. (VNodeKind::Text(old), VNodeKind::Text(new)) => {
  196. let root = old_node.dom_id.get();
  197. if old.text != new.text {
  198. self.edits.push(root);
  199. log::debug!("Text has changed {}, {}", old.text, new.text);
  200. self.edits.set_text(new.text);
  201. self.edits.pop();
  202. }
  203. new_node.dom_id.set(root);
  204. }
  205. (VNodeKind::Element(old), VNodeKind::Element(new)) => {
  206. // If the element type is completely different, the element needs to be re-rendered completely
  207. // This is an optimization React makes due to how users structure their code
  208. //
  209. // In Dioxus, this is less likely to occur unless through a fragment
  210. let root = old_node.dom_id.get();
  211. if new.tag_name != old.tag_name || new.namespace != old.namespace {
  212. self.edits.push(root);
  213. let meta = self.create(new_node);
  214. self.edits.replace_with(meta.added_to_stack);
  215. self.edits.pop();
  216. return;
  217. }
  218. new_node.dom_id.set(root);
  219. // push it just in case
  220. // TODO: remove this - it clogs up things and is inefficient
  221. self.edits.push(root);
  222. self.diff_listeners(old.listeners, new.listeners);
  223. self.diff_attr(old.attributes, new.attributes, new.namespace);
  224. self.diff_children(old.children, new.children);
  225. self.edits.pop();
  226. }
  227. (VNodeKind::Component(old), VNodeKind::Component(new)) => {
  228. log::warn!("diffing components? {:#?}", new.user_fc);
  229. if old.user_fc == new.user_fc {
  230. // Make sure we're dealing with the same component (by function pointer)
  231. // Make sure the new component vnode is referencing the right scope id
  232. let scope_id = old.ass_scope.get();
  233. new.ass_scope.set(scope_id);
  234. // make sure the component's caller function is up to date
  235. let scope = self.components.try_get_mut(scope_id.unwrap()).unwrap();
  236. scope.caller = new.caller.clone();
  237. // ack - this doesn't work on its own!
  238. scope.update_children(new.children);
  239. // React doesn't automatically memoize, but we do.
  240. let should_render = match old.comparator {
  241. Some(comparator) => comparator(new),
  242. None => true,
  243. };
  244. if should_render {
  245. scope.run_scope().unwrap();
  246. self.diff_node(scope.old_frame(), scope.next_frame());
  247. } else {
  248. //
  249. }
  250. self.seen_nodes.insert(scope_id.unwrap());
  251. } else {
  252. // this seems to be a fairy common code path that we could
  253. let mut old_iter = RealChildIterator::new(old_node, &self.components);
  254. let first = old_iter
  255. .next()
  256. .expect("Components should generate a placeholder root");
  257. // remove any leftovers
  258. for to_remove in old_iter {
  259. self.edits.push(to_remove);
  260. self.edits.remove();
  261. }
  262. // seems like we could combine this into a single instruction....
  263. self.edits.push(first);
  264. let meta = self.create(new_node);
  265. self.edits.replace_with(meta.added_to_stack);
  266. self.edits.pop();
  267. // Wipe the old one and plant the new one
  268. let old_scope = old.ass_scope.get().unwrap();
  269. self.destroy_scopes(old_scope);
  270. }
  271. }
  272. (VNodeKind::Fragment(old), VNodeKind::Fragment(new)) => {
  273. // This is the case where options or direct vnodes might be used.
  274. // In this case, it's faster to just skip ahead to their diff
  275. if old.children.len() == 1 && new.children.len() == 1 {
  276. self.diff_node(&old.children[0], &new.children[0]);
  277. return;
  278. }
  279. // Diff using the approach where we're looking for added or removed nodes.
  280. if old.children.len() != new.children.len() {}
  281. // Diff where we think the elements are the same
  282. if old.children.len() == new.children.len() {}
  283. self.diff_children(old.children, new.children);
  284. }
  285. // The strategy here is to pick the first possible node from the previous set and use that as our replace with root
  286. // We also walk the "real node" list to make sure all latent roots are claened up
  287. // This covers the case any time a fragment or component shows up with pretty much anything else
  288. (
  289. VNodeKind::Component(_)
  290. | VNodeKind::Fragment(_)
  291. | VNodeKind::Text(_)
  292. | VNodeKind::Element(_),
  293. VNodeKind::Component(_)
  294. | VNodeKind::Fragment(_)
  295. | VNodeKind::Text(_)
  296. | VNodeKind::Element(_),
  297. ) => {
  298. // Choose the node to use as the placeholder for replacewith
  299. let back_node = match old_node.kind {
  300. // We special case these two types to avoid allocating the small-vecs
  301. VNodeKind::Element(_) | VNodeKind::Text(_) => old_node.dom_id.get(),
  302. _ => {
  303. let mut old_iter = RealChildIterator::new(old_node, &self.components);
  304. let back_node = old_iter
  305. .next()
  306. .expect("Empty fragments should generate a placeholder.");
  307. // remove any leftovers
  308. for to_remove in old_iter {
  309. self.edits.push(to_remove);
  310. self.edits.remove();
  311. }
  312. back_node
  313. }
  314. };
  315. // replace the placeholder or first node with the nodes generated from the "new"
  316. self.edits.push(back_node);
  317. let meta = self.create(new_node);
  318. self.edits.replace_with(meta.added_to_stack);
  319. // todo use the is_static metadata to update this subtree
  320. }
  321. // TODO
  322. (VNodeKind::Suspended { .. }, _) => todo!(),
  323. (_, VNodeKind::Suspended { .. }) => todo!(),
  324. }
  325. }
  326. }
  327. // When we create new nodes, we need to propagate some information back up the call chain.
  328. // This gives the caller some information on how to handle things like insertins, appending, and subtree discarding.
  329. pub struct CreateMeta {
  330. pub is_static: bool,
  331. pub added_to_stack: u32,
  332. }
  333. impl CreateMeta {
  334. fn new(is_static: bool, added_to_tack: u32) -> Self {
  335. Self {
  336. is_static,
  337. added_to_stack: added_to_tack,
  338. }
  339. }
  340. }
  341. impl<'real, 'bump, Dom> DiffMachine<'real, 'bump, Dom>
  342. where
  343. Dom: RealDom<'bump>,
  344. {
  345. // Emit instructions to create the given virtual node.
  346. //
  347. // The change list stack may have any shape upon entering this function:
  348. //
  349. // [...]
  350. //
  351. // When this function returns, the new node is on top of the change list stack:
  352. //
  353. // [... node]
  354. pub fn create(&mut self, node: &'bump VNode<'bump>) -> CreateMeta {
  355. log::warn!("Creating node! ... {:#?}", node);
  356. match &node.kind {
  357. VNodeKind::Text(text) => {
  358. let real_id = self.dom.request_available_node();
  359. self.edits.create_text_node(text.text, real_id);
  360. node.dom_id.set(real_id);
  361. CreateMeta::new(text.is_static, 1)
  362. }
  363. VNodeKind::Element(el) => {
  364. // we have the potential to completely eliminate working on this node in the future(!)
  365. //
  366. // This can only be done if all of the elements properties (attrs, children, listeners, etc) are static
  367. // While creating these things, keep track if we can memoize this element.
  368. // At the end, we'll set this flag on the element to skip it
  369. let mut is_static: bool = true;
  370. let VElement {
  371. tag_name,
  372. listeners,
  373. attributes,
  374. children,
  375. namespace,
  376. static_attrs: _,
  377. static_children: _,
  378. static_listeners: _,
  379. } = el;
  380. let real_id = self.dom.request_available_node();
  381. if let Some(namespace) = namespace {
  382. self.edits
  383. .create_element(tag_name, Some(namespace), real_id)
  384. } else {
  385. self.edits.create_element(tag_name, None, real_id)
  386. };
  387. node.dom_id.set(real_id);
  388. listeners.iter().enumerate().for_each(|(idx, listener)| {
  389. log::info!("setting listener id to {:#?}", real_id);
  390. listener.mounted_node.set(real_id);
  391. self.edits
  392. .new_event_listener(listener.event, listener.scope, idx, real_id);
  393. // if the node has an event listener, then it must be visited ?
  394. is_static = false;
  395. });
  396. for attr in *attributes {
  397. is_static = is_static && attr.is_static;
  398. self.edits
  399. .set_attribute(&attr.name, &attr.value, *namespace);
  400. }
  401. // Fast path: if there is a single text child, it is faster to
  402. // create-and-append the text node all at once via setting the
  403. // parent's `textContent` in a single change list instruction than
  404. // to emit three instructions to (1) create a text node, (2) set its
  405. // text content, and finally (3) append the text node to this
  406. // parent.
  407. //
  408. // Notice: this is a web-specific optimization and may be changed in the future
  409. //
  410. // TODO move over
  411. // if children.len() == 1 {
  412. // if let VNodeKind::Text(text) = &children[0].kind {
  413. // self.edits.set_text(text.text);
  414. // return CreateMeta::new(is_static, 1);
  415. // }
  416. // }
  417. for child in *children {
  418. let child_meta = self.create(child);
  419. is_static = is_static && child_meta.is_static;
  420. // append whatever children were generated by this call
  421. self.edits.append_children(child_meta.added_to_stack);
  422. }
  423. // if is_static {
  424. // log::debug!("created a static node {:#?}", node);
  425. // } else {
  426. // log::debug!("created a dynamic node {:#?}", node);
  427. // }
  428. // el_is_static.set(is_static);
  429. CreateMeta::new(is_static, 1)
  430. }
  431. VNodeKind::Component(vcomponent) => {
  432. log::debug!("Mounting a new component");
  433. let caller = vcomponent.caller.clone();
  434. let parent_idx = self.cur_idx;
  435. // Insert a new scope into our component list
  436. let idx = self
  437. .components
  438. .with(|components| {
  439. components.insert_with_key(|new_idx| {
  440. let parent_scope = self.components.try_get(parent_idx).unwrap();
  441. let height = parent_scope.height + 1;
  442. Scope::new(
  443. caller,
  444. new_idx,
  445. Some(parent_idx),
  446. height,
  447. self.event_queue.new_channel(height, new_idx),
  448. self.components.clone(),
  449. vcomponent.children,
  450. self.task_queue.new_submitter(),
  451. )
  452. })
  453. })
  454. .unwrap();
  455. // This code is supposed to insert the new idx into the parent's descendent list, but it doesn't really work.
  456. // This is mostly used for cleanup - to remove old scopes when components are destroyed.
  457. // TODO
  458. //
  459. // self.components
  460. // .try_get_mut(idx)
  461. // .unwrap()
  462. // .descendents
  463. // .borrow_mut()
  464. // .insert(idx);
  465. // TODO: abstract this unsafe into the arena abstraction
  466. let inner: &'bump mut _ = unsafe { &mut *self.components.components.get() };
  467. let new_component = inner.get_mut(idx).unwrap();
  468. // Actually initialize the caller's slot with the right address
  469. vcomponent.ass_scope.set(Some(idx));
  470. // Run the scope for one iteration to initialize it
  471. new_component.run_scope().unwrap();
  472. // TODO: we need to delete (IE relcaim this node, otherwise the arena will grow infinitely)
  473. let nextnode = new_component.next_frame();
  474. let meta = self.create(nextnode);
  475. // Finally, insert this node as a seen node.
  476. self.seen_nodes.insert(idx);
  477. CreateMeta::new(vcomponent.is_static, meta.added_to_stack)
  478. }
  479. // Fragments are the only nodes that can contain dynamic content (IE through curlies or iterators).
  480. // We can never ignore their contents, so the prescence of a fragment indicates that we need always diff them.
  481. // Fragments will just put all their nodes onto the stack after creation
  482. VNodeKind::Fragment(frag) => {
  483. let mut nodes_added = 0;
  484. for child in frag.children.iter().rev() {
  485. // different types of nodes will generate different amounts on the stack
  486. // nested fragments will spew a ton of nodes onto the stack
  487. // TODO: make sure that our order (.rev) makes sense in a nested situation
  488. let new_meta = self.create(child);
  489. nodes_added += new_meta.added_to_stack;
  490. }
  491. log::info!("This fragment added {} nodes to the stack", nodes_added);
  492. // Never ignore
  493. CreateMeta::new(false, nodes_added)
  494. }
  495. VNodeKind::Suspended => {
  496. let id = self.dom.request_available_node();
  497. self.edits.create_placeholder(id);
  498. node.dom_id.set(id);
  499. CreateMeta::new(false, 1)
  500. }
  501. }
  502. }
  503. }
  504. impl<'a, 'bump, Dom: RealDom<'bump>> DiffMachine<'a, 'bump, Dom> {
  505. /// Destroy a scope and all of its descendents.
  506. ///
  507. /// Calling this will run the destuctors on all hooks in the tree.
  508. /// It will also add the destroyed nodes to the `seen_nodes` cache to prevent them from being renderered.
  509. fn destroy_scopes(&mut self, old_scope: ScopeIdx) {
  510. let mut nodes_to_delete = vec![old_scope];
  511. let mut scopes_to_explore = vec![old_scope];
  512. // explore the scope tree breadth first
  513. while let Some(scope_id) = scopes_to_explore.pop() {
  514. // If we're planning on deleting this node, then we don't need to both rendering it
  515. self.seen_nodes.insert(scope_id);
  516. let scope = self.components.try_get(scope_id).unwrap();
  517. for child in scope.descendents.borrow().iter() {
  518. // Add this node to be explored
  519. scopes_to_explore.push(child.clone());
  520. // Also add it for deletion
  521. nodes_to_delete.push(child.clone());
  522. }
  523. }
  524. // Delete all scopes that we found as part of this subtree
  525. for node in nodes_to_delete {
  526. log::debug!("Removing scope {:#?}", node);
  527. let _scope = self.components.try_remove(node).unwrap();
  528. // do anything we need to do to delete the scope
  529. // I think we need to run the destructors on the hooks
  530. // TODO
  531. }
  532. }
  533. // Diff event listeners between `old` and `new`.
  534. //
  535. // The listeners' node must be on top of the change list stack:
  536. //
  537. // [... node]
  538. //
  539. // The change list stack is left unchanged.
  540. fn diff_listeners(&mut self, old: &[Listener<'_>], new: &[Listener<'_>]) {
  541. if !old.is_empty() || !new.is_empty() {
  542. // self.edits.commit_traversal();
  543. }
  544. // TODO
  545. // what does "diffing listeners" even mean?
  546. 'outer1: for (_l_idx, new_l) in new.iter().enumerate() {
  547. // go through each new listener
  548. // find its corresponding partner in the old list
  549. // if any characteristics changed, remove and then re-add
  550. // if nothing changed, then just move on
  551. let _event_type = new_l.event;
  552. for old_l in old {
  553. if new_l.event == old_l.event {
  554. new_l.mounted_node.set(old_l.mounted_node.get());
  555. // if new_l.id != old_l.id {
  556. // self.edits.remove_event_listener(event_type);
  557. // // TODO! we need to mess with events and assign them by RealDomNode
  558. // // self.edits
  559. // // .update_event_listener(event_type, new_l.scope, new_l.id)
  560. // }
  561. continue 'outer1;
  562. }
  563. }
  564. // self.edits
  565. // .new_event_listener(event_type, new_l.scope, new_l.id);
  566. }
  567. // 'outer2: for old_l in old {
  568. // for new_l in new {
  569. // if new_l.event == old_l.event {
  570. // continue 'outer2;
  571. // }
  572. // }
  573. // self.edits.remove_event_listener(old_l.event);
  574. // }
  575. }
  576. // Diff a node's attributes.
  577. //
  578. // The attributes' node must be on top of the change list stack:
  579. //
  580. // [... node]
  581. //
  582. // The change list stack is left unchanged.
  583. fn diff_attr(
  584. &mut self,
  585. old: &'bump [Attribute<'bump>],
  586. new: &'bump [Attribute<'bump>],
  587. namespace: Option<&'static str>,
  588. ) {
  589. // Do O(n^2) passes to add/update and remove attributes, since
  590. // there are almost always very few attributes.
  591. //
  592. // The "fast" path is when the list of attributes name is identical and in the same order
  593. // With the Rsx and Html macros, this will almost always be the case
  594. 'outer: for new_attr in new {
  595. if new_attr.is_volatile {
  596. // self.edits.commit_traversal();
  597. self.edits
  598. .set_attribute(new_attr.name, new_attr.value, namespace);
  599. } else {
  600. for old_attr in old {
  601. if old_attr.name == new_attr.name {
  602. if old_attr.value != new_attr.value {
  603. // self.edits.commit_traversal();
  604. self.edits
  605. .set_attribute(new_attr.name, new_attr.value, namespace);
  606. }
  607. continue 'outer;
  608. } else {
  609. // names are different, a varying order of attributes has arrived
  610. }
  611. }
  612. // self.edits.commit_traversal();
  613. self.edits
  614. .set_attribute(new_attr.name, new_attr.value, namespace);
  615. }
  616. }
  617. 'outer2: for old_attr in old {
  618. for new_attr in new {
  619. if old_attr.name == new_attr.name {
  620. continue 'outer2;
  621. }
  622. }
  623. // self.edits.commit_traversal();
  624. self.edits.remove_attribute(old_attr.name);
  625. }
  626. }
  627. // Diff the given set of old and new children.
  628. //
  629. // The parent must be on top of the change list stack when this function is
  630. // entered:
  631. //
  632. // [... parent]
  633. //
  634. // the change list stack is in the same state when this function returns.
  635. fn diff_children(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
  636. if new.is_empty() {
  637. if !old.is_empty() {
  638. // self.edits.commit_traversal();
  639. self.remove_all_children(old);
  640. }
  641. return;
  642. }
  643. if new.len() == 1 {
  644. match (&old.first(), &new[0]) {
  645. // (Some(VNodeKind::Text(old_vtext)), VNodeKind::Text(new_vtext))
  646. // if old_vtext.text == new_vtext.text =>
  647. // {
  648. // // Don't take this fast path...
  649. // }
  650. // (_, VNodeKind::Text(text)) => {
  651. // // self.edits.commit_traversal();
  652. // log::debug!("using optimized text set");
  653. // self.edits.set_text(text.text);
  654. // return;
  655. // }
  656. // todo: any more optimizations
  657. (_, _) => {}
  658. }
  659. }
  660. if old.is_empty() {
  661. if !new.is_empty() {
  662. // self.edits.commit_traversal();
  663. self.create_and_append_children(new);
  664. }
  665. return;
  666. }
  667. let new_is_keyed = new[0].key.is_some();
  668. let old_is_keyed = old[0].key.is_some();
  669. debug_assert!(
  670. new.iter().all(|n| n.key.is_some() == new_is_keyed),
  671. "all siblings must be keyed or all siblings must be non-keyed"
  672. );
  673. debug_assert!(
  674. old.iter().all(|o| o.key.is_some() == old_is_keyed),
  675. "all siblings must be keyed or all siblings must be non-keyed"
  676. );
  677. if new_is_keyed && old_is_keyed {
  678. log::warn!("using the wrong approach");
  679. self.diff_non_keyed_children(old, new);
  680. // todo!("Not yet implemented a migration away from temporaries");
  681. // let t = self.edits.next_temporary();
  682. // self.diff_keyed_children(old, new);
  683. // self.edits.set_next_temporary(t);
  684. } else {
  685. // log::debug!("diffing non keyed children");
  686. self.diff_non_keyed_children(old, new);
  687. }
  688. }
  689. // Diffing "keyed" children.
  690. //
  691. // With keyed children, we care about whether we delete, move, or create nodes
  692. // versus mutate existing nodes in place. Presumably there is some sort of CSS
  693. // transition animation that makes the virtual DOM diffing algorithm
  694. // observable. By specifying keys for nodes, we know which virtual DOM nodes
  695. // must reuse (or not reuse) the same physical DOM nodes.
  696. //
  697. // This is loosely based on Inferno's keyed patching implementation. However, we
  698. // have to modify the algorithm since we are compiling the diff down into change
  699. // list instructions that will be executed later, rather than applying the
  700. // changes to the DOM directly as we compare virtual DOMs.
  701. //
  702. // https://github.com/infernojs/inferno/blob/36fd96/packages/inferno/src/DOM/patching.ts#L530-L739
  703. //
  704. // When entering this function, the parent must be on top of the change list
  705. // stack:
  706. //
  707. // [... parent]
  708. //
  709. // Upon exiting, the change list stack is in the same state.
  710. fn diff_keyed_children(&self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
  711. // todo!();
  712. if cfg!(debug_assertions) {
  713. let mut keys = fxhash::FxHashSet::default();
  714. let mut assert_unique_keys = |children: &'bump [VNode<'bump>]| {
  715. keys.clear();
  716. for child in children {
  717. let key = child.key;
  718. debug_assert!(
  719. key.is_some(),
  720. "if any sibling is keyed, all siblings must be keyed"
  721. );
  722. keys.insert(key);
  723. }
  724. debug_assert_eq!(
  725. children.len(),
  726. keys.len(),
  727. "keyed siblings must each have a unique key"
  728. );
  729. };
  730. assert_unique_keys(old);
  731. assert_unique_keys(new);
  732. }
  733. // First up, we diff all the nodes with the same key at the beginning of the
  734. // children.
  735. //
  736. // `shared_prefix_count` is the count of how many nodes at the start of
  737. // `new` and `old` share the same keys.
  738. let shared_prefix_count = match self.diff_keyed_prefix(old, new) {
  739. KeyedPrefixResult::Finished => return,
  740. KeyedPrefixResult::MoreWorkToDo(count) => count,
  741. };
  742. match self.diff_keyed_prefix(old, new) {
  743. KeyedPrefixResult::Finished => return,
  744. KeyedPrefixResult::MoreWorkToDo(count) => count,
  745. };
  746. // Next, we find out how many of the nodes at the end of the children have
  747. // the same key. We do _not_ diff them yet, since we want to emit the change
  748. // list instructions such that they can be applied in a single pass over the
  749. // DOM. Instead, we just save this information for later.
  750. //
  751. // `shared_suffix_count` is the count of how many nodes at the end of `new`
  752. // and `old` share the same keys.
  753. let shared_suffix_count = old[shared_prefix_count..]
  754. .iter()
  755. .rev()
  756. .zip(new[shared_prefix_count..].iter().rev())
  757. .take_while(|&(old, new)| old.key == new.key)
  758. .count();
  759. let old_shared_suffix_start = old.len() - shared_suffix_count;
  760. let new_shared_suffix_start = new.len() - shared_suffix_count;
  761. // Ok, we now hopefully have a smaller range of children in the middle
  762. // within which to re-order nodes with the same keys, remove old nodes with
  763. // now-unused keys, and create new nodes with fresh keys.
  764. self.diff_keyed_middle(
  765. &old[shared_prefix_count..old_shared_suffix_start],
  766. &new[shared_prefix_count..new_shared_suffix_start],
  767. shared_prefix_count,
  768. shared_suffix_count,
  769. old_shared_suffix_start,
  770. );
  771. // Finally, diff the nodes at the end of `old` and `new` that share keys.
  772. let old_suffix = &old[old_shared_suffix_start..];
  773. let new_suffix = &new[new_shared_suffix_start..];
  774. debug_assert_eq!(old_suffix.len(), new_suffix.len());
  775. if !old_suffix.is_empty() {
  776. self.diff_keyed_suffix(old_suffix, new_suffix, new_shared_suffix_start)
  777. }
  778. }
  779. // Diff the prefix of children in `new` and `old` that share the same keys in
  780. // the same order.
  781. //
  782. // Upon entry of this function, the change list stack must be:
  783. //
  784. // [... parent]
  785. //
  786. // Upon exit, the change list stack is the same.
  787. fn diff_keyed_prefix(
  788. &self,
  789. _old: &'bump [VNode<'bump>],
  790. _new: &'bump [VNode<'bump>],
  791. ) -> KeyedPrefixResult {
  792. todo!()
  793. // self.edits.go_down();
  794. // let mut shared_prefix_count = 0;
  795. // for (i, (old, new)) in old.iter().zip(new.iter()).enumerate() {
  796. // if old.key() != new.key() {
  797. // break;
  798. // }
  799. // self.edits.go_to_sibling(i);
  800. // self.diff_node(old, new);
  801. // shared_prefix_count += 1;
  802. // }
  803. // // If that was all of the old children, then create and append the remaining
  804. // // new children and we're finished.
  805. // if shared_prefix_count == old.len() {
  806. // self.edits.go_up();
  807. // // self.edits.commit_traversal();
  808. // self.create_and_append_children(&new[shared_prefix_count..]);
  809. // return KeyedPrefixResult::Finished;
  810. // }
  811. // // And if that was all of the new children, then remove all of the remaining
  812. // // old children and we're finished.
  813. // if shared_prefix_count == new.len() {
  814. // self.edits.go_to_sibling(shared_prefix_count);
  815. // // self.edits.commit_traversal();
  816. // self.remove_self_and_next_siblings(&old[shared_prefix_count..]);
  817. // return KeyedPrefixResult::Finished;
  818. // }
  819. // self.edits.go_up();
  820. // KeyedPrefixResult::MoreWorkToDo(shared_prefix_count)
  821. }
  822. // Remove all of a node's children.
  823. //
  824. // The change list stack must have this shape upon entry to this function:
  825. //
  826. // [... parent]
  827. //
  828. // When this function returns, the change list stack is in the same state.
  829. pub fn remove_all_children(&mut self, old: &'bump [VNode<'bump>]) {
  830. // debug_assert!(self.edits.traversal_is_committed());
  831. log::debug!("REMOVING CHILDREN");
  832. for _child in old {
  833. // registry.remove_subtree(child);
  834. }
  835. // Fast way to remove all children: set the node's textContent to an empty
  836. // string.
  837. todo!()
  838. // self.edits.set_inner_text("");
  839. }
  840. // Create the given children and append them to the parent node.
  841. //
  842. // The parent node must currently be on top of the change list stack:
  843. //
  844. // [... parent]
  845. //
  846. // When this function returns, the change list stack is in the same state.
  847. pub fn create_and_append_children(&mut self, new: &'bump [VNode<'bump>]) {
  848. for child in new {
  849. let meta = self.create(child);
  850. self.edits.append_children(meta.added_to_stack);
  851. }
  852. }
  853. // The most-general, expensive code path for keyed children diffing.
  854. //
  855. // We find the longest subsequence within `old` of children that are relatively
  856. // ordered the same way in `new` (via finding a longest-increasing-subsequence
  857. // of the old child's index within `new`). The children that are elements of
  858. // this subsequence will remain in place, minimizing the number of DOM moves we
  859. // will have to do.
  860. //
  861. // Upon entry to this function, the change list stack must be:
  862. //
  863. // [... parent]
  864. //
  865. // Upon exit from this function, it will be restored to that same state.
  866. fn diff_keyed_middle(
  867. &self,
  868. _old: &[VNode<'bump>],
  869. _new: &[VNode<'bump>],
  870. _shared_prefix_count: usize,
  871. _shared_suffix_count: usize,
  872. _old_shared_suffix_start: usize,
  873. ) {
  874. todo!()
  875. // // Should have already diffed the shared-key prefixes and suffixes.
  876. // debug_assert_ne!(new.first().map(|n| n.key()), old.first().map(|o| o.key()));
  877. // debug_assert_ne!(new.last().map(|n| n.key()), old.last().map(|o| o.key()));
  878. // // The algorithm below relies upon using `u32::MAX` as a sentinel
  879. // // value, so if we have that many new nodes, it won't work. This
  880. // // check is a bit academic (hence only enabled in debug), since
  881. // // wasm32 doesn't have enough address space to hold that many nodes
  882. // // in memory.
  883. // debug_assert!(new.len() < u32::MAX as usize);
  884. // // Map from each `old` node's key to its index within `old`.
  885. // let mut old_key_to_old_index = FxHashMap::default();
  886. // old_key_to_old_index.reserve(old.len());
  887. // old_key_to_old_index.extend(old.iter().enumerate().map(|(i, o)| (o.key(), i)));
  888. // // The set of shared keys between `new` and `old`.
  889. // let mut shared_keys = FxHashSet::default();
  890. // // Map from each index in `new` to the index of the node in `old` that
  891. // // has the same key.
  892. // let mut new_index_to_old_index = Vec::with_capacity(new.len());
  893. // new_index_to_old_index.extend(new.iter().map(|n| {
  894. // let key = n.key();
  895. // if let Some(&i) = old_key_to_old_index.get(&key) {
  896. // shared_keys.insert(key);
  897. // i
  898. // } else {
  899. // u32::MAX as usize
  900. // }
  901. // }));
  902. // // If none of the old keys are reused by the new children, then we
  903. // // remove all the remaining old children and create the new children
  904. // // afresh.
  905. // if shared_suffix_count == 0 && shared_keys.is_empty() {
  906. // if shared_prefix_count == 0 {
  907. // // self.edits.commit_traversal();
  908. // self.remove_all_children(old);
  909. // } else {
  910. // self.edits.go_down_to_child(shared_prefix_count);
  911. // // self.edits.commit_traversal();
  912. // self.remove_self_and_next_siblings(&old[shared_prefix_count..]);
  913. // }
  914. // self.create_and_append_children(new);
  915. // return;
  916. // }
  917. // // Save each of the old children whose keys are reused in the new
  918. // // children.
  919. // let mut old_index_to_temp = vec![u32::MAX; old.len()];
  920. // let mut start = 0;
  921. // loop {
  922. // let end = (start..old.len())
  923. // .find(|&i| {
  924. // let key = old[i].key();
  925. // !shared_keys.contains(&key)
  926. // })
  927. // .unwrap_or(old.len());
  928. // if end - start > 0 {
  929. // // self.edits.commit_traversal();
  930. // let mut t = self.edits.save_children_to_temporaries(
  931. // shared_prefix_count + start,
  932. // shared_prefix_count + end,
  933. // );
  934. // for i in start..end {
  935. // old_index_to_temp[i] = t;
  936. // t += 1;
  937. // }
  938. // }
  939. // debug_assert!(end <= old.len());
  940. // if end == old.len() {
  941. // break;
  942. // } else {
  943. // start = end + 1;
  944. // }
  945. // }
  946. // // Remove any old children whose keys were not reused in the new
  947. // // children. Remove from the end first so that we don't mess up indices.
  948. // let mut removed_count = 0;
  949. // for (i, old_child) in old.iter().enumerate().rev() {
  950. // if !shared_keys.contains(&old_child.key()) {
  951. // // registry.remove_subtree(old_child);
  952. // // todo
  953. // // self.edits.commit_traversal();
  954. // self.edits.remove_child(i + shared_prefix_count);
  955. // removed_count += 1;
  956. // }
  957. // }
  958. // // If there aren't any more new children, then we are done!
  959. // if new.is_empty() {
  960. // return;
  961. // }
  962. // // The longest increasing subsequence within `new_index_to_old_index`. This
  963. // // is the longest sequence on DOM nodes in `old` that are relatively ordered
  964. // // correctly within `new`. We will leave these nodes in place in the DOM,
  965. // // and only move nodes that are not part of the LIS. This results in the
  966. // // maximum number of DOM nodes left in place, AKA the minimum number of DOM
  967. // // nodes moved.
  968. // let mut new_index_is_in_lis = FxHashSet::default();
  969. // new_index_is_in_lis.reserve(new_index_to_old_index.len());
  970. // let mut predecessors = vec![0; new_index_to_old_index.len()];
  971. // let mut starts = vec![0; new_index_to_old_index.len()];
  972. // longest_increasing_subsequence::lis_with(
  973. // &new_index_to_old_index,
  974. // &mut new_index_is_in_lis,
  975. // |a, b| a < b,
  976. // &mut predecessors,
  977. // &mut starts,
  978. // );
  979. // // Now we will iterate from the end of the new children back to the
  980. // // beginning, diffing old children we are reusing and if they aren't in the
  981. // // LIS moving them to their new destination, or creating new children. Note
  982. // // that iterating in reverse order lets us use `Node.prototype.insertBefore`
  983. // // to move/insert children.
  984. // //
  985. // // But first, we ensure that we have a child on the change list stack that
  986. // // we can `insertBefore`. We handle this once before looping over `new`
  987. // // children, so that we don't have to keep checking on every loop iteration.
  988. // if shared_suffix_count > 0 {
  989. // // There is a shared suffix after these middle children. We will be
  990. // // inserting before that shared suffix, so add the first child of that
  991. // // shared suffix to the change list stack.
  992. // //
  993. // // [... parent]
  994. // self.edits
  995. // .go_down_to_child(old_shared_suffix_start - removed_count);
  996. // // [... parent first_child_of_shared_suffix]
  997. // } else {
  998. // // There is no shared suffix coming after these middle children.
  999. // // Therefore we have to process the last child in `new` and move it to
  1000. // // the end of the parent's children if it isn't already there.
  1001. // let last_index = new.len() - 1;
  1002. // // uhhhh why an unwrap?
  1003. // let last = new.last().unwrap();
  1004. // // let last = new.last().unwrap_throw();
  1005. // new = &new[..new.len() - 1];
  1006. // if shared_keys.contains(&last.key()) {
  1007. // let old_index = new_index_to_old_index[last_index];
  1008. // let temp = old_index_to_temp[old_index];
  1009. // // [... parent]
  1010. // self.edits.go_down_to_temp_child(temp);
  1011. // // [... parent last]
  1012. // self.diff_node(&old[old_index], last);
  1013. // if new_index_is_in_lis.contains(&last_index) {
  1014. // // Don't move it, since it is already where it needs to be.
  1015. // } else {
  1016. // // self.edits.commit_traversal();
  1017. // // [... parent last]
  1018. // self.edits.append_child();
  1019. // // [... parent]
  1020. // self.edits.go_down_to_temp_child(temp);
  1021. // // [... parent last]
  1022. // }
  1023. // } else {
  1024. // // self.edits.commit_traversal();
  1025. // // [... parent]
  1026. // self.create(last);
  1027. // // [... parent last]
  1028. // self.edits.append_child();
  1029. // // [... parent]
  1030. // self.edits.go_down_to_reverse_child(0);
  1031. // // [... parent last]
  1032. // }
  1033. // }
  1034. // for (new_index, new_child) in new.iter().enumerate().rev() {
  1035. // let old_index = new_index_to_old_index[new_index];
  1036. // if old_index == u32::MAX as usize {
  1037. // debug_assert!(!shared_keys.contains(&new_child.key()));
  1038. // // self.edits.commit_traversal();
  1039. // // [... parent successor]
  1040. // self.create(new_child);
  1041. // // [... parent successor new_child]
  1042. // self.edits.insert_before();
  1043. // // [... parent new_child]
  1044. // } else {
  1045. // debug_assert!(shared_keys.contains(&new_child.key()));
  1046. // let temp = old_index_to_temp[old_index];
  1047. // debug_assert_ne!(temp, u32::MAX);
  1048. // if new_index_is_in_lis.contains(&new_index) {
  1049. // // [... parent successor]
  1050. // self.edits.go_to_temp_sibling(temp);
  1051. // // [... parent new_child]
  1052. // } else {
  1053. // // self.edits.commit_traversal();
  1054. // // [... parent successor]
  1055. // self.edits.push_temporary(temp);
  1056. // // [... parent successor new_child]
  1057. // self.edits.insert_before();
  1058. // // [... parent new_child]
  1059. // }
  1060. // self.diff_node(&old[old_index], new_child);
  1061. // }
  1062. // }
  1063. // // [... parent child]
  1064. // self.edits.go_up();
  1065. // [... parent]
  1066. }
  1067. // Diff the suffix of keyed children that share the same keys in the same order.
  1068. //
  1069. // The parent must be on the change list stack when we enter this function:
  1070. //
  1071. // [... parent]
  1072. //
  1073. // When this function exits, the change list stack remains the same.
  1074. fn diff_keyed_suffix(
  1075. &self,
  1076. _old: &[VNode<'bump>],
  1077. _new: &[VNode<'bump>],
  1078. _new_shared_suffix_start: usize,
  1079. ) {
  1080. todo!()
  1081. // debug_assert_eq!(old.len(), new.len());
  1082. // debug_assert!(!old.is_empty());
  1083. // // [... parent]
  1084. // self.edits.go_down();
  1085. // // [... parent new_child]
  1086. // for (i, (old_child, new_child)) in old.iter().zip(new.iter()).enumerate() {
  1087. // self.edits.go_to_sibling(new_shared_suffix_start + i);
  1088. // self.diff_node(old_child, new_child);
  1089. // }
  1090. // // [... parent]
  1091. // self.edits.go_up();
  1092. }
  1093. // Diff children that are not keyed.
  1094. //
  1095. // The parent must be on the top of the change list stack when entering this
  1096. // function:
  1097. //
  1098. // [... parent]
  1099. //
  1100. // the change list stack is in the same state when this function returns.
  1101. fn diff_non_keyed_children(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
  1102. // Handled these cases in `diff_children` before calling this function.
  1103. debug_assert!(!new.is_empty());
  1104. debug_assert!(!old.is_empty());
  1105. // [... parent]
  1106. // self.edits.go_down();
  1107. // self.edits.push_root()
  1108. // [... parent child]
  1109. // todo!()
  1110. for (_i, (new_child, old_child)) in new.iter().zip(old.iter()).enumerate() {
  1111. // [... parent prev_child]
  1112. // self.edits.go_to_sibling(i);
  1113. // [... parent this_child]
  1114. // let did = old_child.get_mounted_id(self.components).unwrap();
  1115. // if did.0 == 0 {
  1116. // log::debug!("Root is bad: {:#?}", old_child);
  1117. // }
  1118. // self.edits.push_root(did);
  1119. self.diff_node(old_child, new_child);
  1120. // let old_id = old_child.get_mounted_id(self.components).unwrap();
  1121. // let new_id = new_child.get_mounted_id(self.components).unwrap();
  1122. // log::debug!(
  1123. // "pushed root. {:?}, {:?}",
  1124. // old_child.get_mounted_id(self.components).unwrap(),
  1125. // new_child.get_mounted_id(self.components).unwrap()
  1126. // );
  1127. // if old_id != new_id {
  1128. // log::debug!("Mismatch: {:?}", new_child);
  1129. // }
  1130. }
  1131. // match old.len().cmp(&new.len()) {
  1132. // // old.len > new.len -> removing some nodes
  1133. // Ordering::Greater => {
  1134. // // [... parent prev_child]
  1135. // self.edits.go_to_sibling(new.len());
  1136. // // [... parent first_child_to_remove]
  1137. // // self.edits.commit_traversal();
  1138. // // support::remove_self_and_next_siblings(state, &old[new.len()..]);
  1139. // self.remove_self_and_next_siblings(&old[new.len()..]);
  1140. // // [... parent]
  1141. // }
  1142. // // old.len < new.len -> adding some nodes
  1143. // Ordering::Less => {
  1144. // // [... parent last_child]
  1145. // self.edits.go_up();
  1146. // // [... parent]
  1147. // // self.edits.commit_traversal();
  1148. // self.create_and_append_children(&new[old.len()..]);
  1149. // }
  1150. // // old.len == new.len -> no nodes added/removed, but πerhaps changed
  1151. // Ordering::Equal => {
  1152. // // [... parent child]
  1153. // self.edits.go_up();
  1154. // // [... parent]
  1155. // }
  1156. // }
  1157. }
  1158. // ======================
  1159. // Support methods
  1160. // ======================
  1161. // Remove the current child and all of its following siblings.
  1162. //
  1163. // The change list stack must have this shape upon entry to this function:
  1164. //
  1165. // [... parent child]
  1166. //
  1167. // After the function returns, the child is no longer on the change list stack:
  1168. //
  1169. // [... parent]
  1170. pub fn remove_self_and_next_siblings(&self, old: &[VNode<'bump>]) {
  1171. // debug_assert!(self.edits.traversal_is_committed());
  1172. for child in old {
  1173. if let VNodeKind::Component(_vcomp) = child.kind {
  1174. // dom
  1175. // .create_text_node("placeholder for vcomponent");
  1176. todo!()
  1177. // let root_id = vcomp.stable_addr.as_ref().borrow().unwrap();
  1178. // self.lifecycle_events.push_back(LifeCycleEvent::Remove {
  1179. // root_id,
  1180. // stable_scope_addr: Rc::downgrade(&vcomp.ass_scope),
  1181. // })
  1182. // let id = get_id();
  1183. // *component.stable_addr.as_ref().borrow_mut() = Some(id);
  1184. // self.edits.save_known_root(id);
  1185. // let scope = Rc::downgrade(&component.ass_scope);
  1186. // self.lifecycle_events.push_back(LifeCycleEvent::Mount {
  1187. // caller: Rc::downgrade(&component.caller),
  1188. // root_id: id,
  1189. // stable_scope_addr: scope,
  1190. // });
  1191. }
  1192. // registry.remove_subtree(child);
  1193. }
  1194. todo!()
  1195. // self.edits.remove_self_and_next_siblings();
  1196. }
  1197. }
  1198. enum KeyedPrefixResult {
  1199. // Fast path: we finished diffing all the children just by looking at the
  1200. // prefix of shared keys!
  1201. Finished,
  1202. // There is more diffing work to do. Here is a count of how many children at
  1203. // the beginning of `new` and `old` we already processed.
  1204. MoreWorkToDo(usize),
  1205. }
  1206. /// This iterator iterates through a list of virtual children and only returns real children (Elements or Text).
  1207. ///
  1208. /// This iterator is useful when it's important to load the next real root onto the top of the stack for operations like
  1209. /// "InsertBefore".
  1210. struct RealChildIterator<'a> {
  1211. scopes: &'a SharedArena,
  1212. // Heuristcally we should never bleed into 4 completely nested fragments/components
  1213. // Smallvec lets us stack allocate our little stack machine so the vast majority of cases are sane
  1214. // TODO: use const generics instead of the 4 estimation
  1215. stack: smallvec::SmallVec<[(u16, &'a VNode<'a>); 4]>,
  1216. }
  1217. impl<'a> RealChildIterator<'a> {
  1218. fn new(starter: &'a VNode<'a>, scopes: &'a SharedArena) -> Self {
  1219. Self {
  1220. scopes,
  1221. stack: smallvec::smallvec![(0, starter)],
  1222. }
  1223. }
  1224. }
  1225. impl<'a> Iterator for RealChildIterator<'a> {
  1226. type Item = RealDomNode;
  1227. fn next(&mut self) -> Option<RealDomNode> {
  1228. let mut should_pop = false;
  1229. let mut returned_node = None;
  1230. let mut should_push = None;
  1231. while returned_node.is_none() {
  1232. if let Some((count, node)) = self.stack.last_mut() {
  1233. match &node.kind {
  1234. // We can only exit our looping when we get "real" nodes
  1235. // This includes fragments and components when they're empty (have a single root)
  1236. VNodeKind::Element(_) | VNodeKind::Text(_) => {
  1237. // We've recursed INTO an element/text
  1238. // We need to recurse *out* of it and move forward to the next
  1239. should_pop = true;
  1240. returned_node = Some(node.dom_id.get());
  1241. }
  1242. // If we get a fragment we push the next child
  1243. VNodeKind::Fragment(frag) => {
  1244. let subcount = *count as usize;
  1245. if frag.children.len() == 0 {
  1246. should_pop = true;
  1247. returned_node = Some(node.dom_id.get());
  1248. }
  1249. if subcount >= frag.children.len() {
  1250. should_pop = true;
  1251. } else {
  1252. should_push = Some(&frag.children[subcount]);
  1253. }
  1254. }
  1255. // Immediately abort suspended nodes - can't do anything with them yet
  1256. // VNodeKind::Suspended => should_pop = true,
  1257. VNodeKind::Suspended => todo!(),
  1258. // For components, we load their root and push them onto the stack
  1259. VNodeKind::Component(sc) => {
  1260. let scope = self.scopes.try_get(sc.ass_scope.get().unwrap()).unwrap();
  1261. // Simply swap the current node on the stack with the root of the component
  1262. *node = scope.root();
  1263. }
  1264. }
  1265. } else {
  1266. // If there's no more items on the stack, we're done!
  1267. return None;
  1268. }
  1269. if should_pop {
  1270. self.stack.pop();
  1271. if let Some((id, _)) = self.stack.last_mut() {
  1272. *id += 1;
  1273. }
  1274. should_pop = false;
  1275. }
  1276. if let Some(push) = should_push {
  1277. self.stack.push((0, push));
  1278. should_push = None;
  1279. }
  1280. }
  1281. returned_node
  1282. }
  1283. }
  1284. fn compare_strs(a: &str, b: &str) -> bool {
  1285. // Check by pointer, optimizing for static strs
  1286. if !std::ptr::eq(a, b) {
  1287. // If the pointers are different then check by value
  1288. a == b
  1289. } else {
  1290. true
  1291. }
  1292. }