node.rs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970
  1. use crate::{Attribute, AttributeValue, DynamicNode::*};
  2. use crate::{VNode, VirtualDom, WriteMutations};
  3. use core::iter::Peekable;
  4. use std::cell::Ref;
  5. use std::cell::RefMut;
  6. use crate::{
  7. arena::ElementId,
  8. innerlude::{ElementPath, ElementRef, VComponent, VNodeMount, VText},
  9. nodes::DynamicNode,
  10. nodes::RenderReturn,
  11. scopes::ScopeId,
  12. TemplateNode,
  13. TemplateNode::*,
  14. };
  15. impl VNode {
  16. pub(crate) fn diff_node(
  17. &self,
  18. new: &VNode,
  19. dom: &mut VirtualDom,
  20. to: &mut impl WriteMutations,
  21. ) {
  22. // If hot reloading is enabled, we need to make sure we're using the latest template
  23. #[cfg(debug_assertions)]
  24. {
  25. let (path, byte_index) = new.template.get().name.rsplit_once(':').unwrap();
  26. if let Some(map) = dom.templates.get(path) {
  27. let byte_index = byte_index.parse::<usize>().unwrap();
  28. if let Some(&template) = map.get(&byte_index) {
  29. new.template.set(template);
  30. if template != self.template.get() {
  31. let parent = self.parent();
  32. return self.replace([new], parent, dom, to);
  33. }
  34. }
  35. }
  36. }
  37. {
  38. // Copy over the mount information
  39. *new.mount.borrow_mut() = self.mount.borrow_mut().take();
  40. }
  41. // If the templates are the same, we don't need to do anything, except copy over the mount information
  42. if self == new {
  43. return;
  44. }
  45. // If the templates are different by name, we need to replace the entire template
  46. if self.templates_are_different(new) {
  47. return self.light_diff_templates(new, dom, to);
  48. }
  49. let mut mount = self.assert_mounted_mut();
  50. let mount = &mut *mount;
  51. // If the templates are the same, we can diff the attributes and children
  52. // Start with the attributes
  53. self.dynamic_attrs
  54. .iter()
  55. .zip(new.dynamic_attrs.iter())
  56. .enumerate()
  57. .for_each(|(idx, (old_attr, new_attr))| {
  58. // If the attributes are different (or volatile), we need to update them
  59. if old_attr.value != new_attr.value || new_attr.volatile {
  60. self.update_attribute(mount, idx, new_attr, to);
  61. }
  62. });
  63. // Now diff the dynamic nodes
  64. self.dynamic_nodes
  65. .iter()
  66. .zip(new.dynamic_nodes.iter())
  67. .enumerate()
  68. .for_each(|(dyn_node_idx, (old, new))| {
  69. self.diff_dynamic_node(mount, dyn_node_idx, old, new, dom, to)
  70. });
  71. }
  72. /// Push all the real nodes on the stack
  73. pub(crate) fn push_all_real_nodes(
  74. &self,
  75. dom: &VirtualDom,
  76. to: &mut impl WriteMutations,
  77. ) -> usize {
  78. let template = self.template.get();
  79. let mount = self.assert_mounted();
  80. template
  81. .roots
  82. .iter()
  83. .enumerate()
  84. .map(|(root_idx, _)| match &self.template.get().roots[root_idx] {
  85. Dynamic { id: idx } => match &self.dynamic_nodes[*idx] {
  86. Placeholder(_) | Text(_) => {
  87. to.push_root(mount.root_ids[root_idx]);
  88. 1
  89. }
  90. Fragment(nodes) => {
  91. let mut accumulated = 0;
  92. for node in nodes {
  93. accumulated += node.push_all_real_nodes(dom, to);
  94. }
  95. accumulated
  96. }
  97. Component(_) => {
  98. let scope = ScopeId(mount.mounted_dynamic_nodes[*idx]);
  99. let node = dom.get_scope(scope).unwrap().root_node();
  100. node.push_all_real_nodes(dom, to)
  101. }
  102. },
  103. _ => {
  104. to.push_root(mount.root_ids[root_idx]);
  105. 1
  106. }
  107. })
  108. .sum()
  109. }
  110. fn diff_dynamic_node(
  111. &self,
  112. mount: &mut VNodeMount,
  113. idx: usize,
  114. old_node: &DynamicNode,
  115. new_node: &DynamicNode,
  116. dom: &mut VirtualDom,
  117. to: &mut impl WriteMutations,
  118. ) {
  119. let parent = || ElementRef {
  120. element: self.clone_with_parent(),
  121. path: ElementPath {
  122. path: self.template.get().node_paths[idx],
  123. },
  124. };
  125. match (old_node, new_node) {
  126. (Text(old), Text(new)) => self.diff_vtext( to, mount, idx, old, new),
  127. (Placeholder(_), Placeholder(_)) => {},
  128. (Fragment(old), Fragment(new)) => dom.diff_non_empty_fragment(to, old, new, Some(parent())),
  129. (Component(old), Component(new)) => {
  130. let scope_id = ScopeId(mount.mounted_dynamic_nodes[idx]);
  131. self.diff_vcomponent(mount, idx, new, old, scope_id, Some(parent()), dom, to)
  132. },
  133. (Placeholder(_), Fragment(right)) => {
  134. let placeholder_id = ElementId(mount.mounted_dynamic_nodes[idx]);
  135. dom.replace_placeholder(to, placeholder_id, right, Some(parent()))},
  136. (Fragment(left), Placeholder(_)) => {
  137. dom.nodes_to_placeholder(to, mount, idx, left,)
  138. },
  139. _ => todo!("This is an usual custom case for dynamic nodes. We don't know how to handle it yet."),
  140. };
  141. }
  142. pub(crate) fn find_first_element(&self, dom: &VirtualDom) -> ElementId {
  143. let mount = self.assert_mounted();
  144. match &self.template.get().roots[0] {
  145. TemplateNode::Element { .. } | TemplateNode::Text { text: _ } => mount.root_ids[0],
  146. TemplateNode::Dynamic { id } | TemplateNode::DynamicText { id } => {
  147. match &self.dynamic_nodes[*id] {
  148. Placeholder(_) | Text(_) => ElementId(mount.mounted_dynamic_nodes[*id]),
  149. Fragment(children) => {
  150. let child = children.first().unwrap();
  151. child.find_first_element(dom)
  152. }
  153. Component(_comp) => {
  154. let scope = ScopeId(mount.mounted_dynamic_nodes[*id]);
  155. match dom.get_scope(scope).unwrap().root_node() {
  156. RenderReturn::Ready(child) => child.find_first_element(dom),
  157. _ => todo!("cannot handle nonstandard nodes"),
  158. }
  159. }
  160. }
  161. }
  162. }
  163. }
  164. pub(crate) fn find_last_element(&self, dom: &VirtualDom) -> ElementId {
  165. let mount = self.assert_mounted();
  166. match &self.template.get().roots.last().unwrap() {
  167. TemplateNode::Element { .. } | TemplateNode::Text { text: _ } => {
  168. *mount.root_ids.last().unwrap()
  169. }
  170. TemplateNode::Dynamic { id } | TemplateNode::DynamicText { id } => {
  171. match &self.dynamic_nodes[*id] {
  172. Placeholder(_) | Text(_) => ElementId(mount.mounted_dynamic_nodes[*id]),
  173. Fragment(t) => t.last().unwrap().find_last_element(dom),
  174. Component(_comp) => {
  175. let scope = ScopeId(mount.mounted_dynamic_nodes[*id]);
  176. match dom.get_scope(scope).unwrap().root_node() {
  177. RenderReturn::Ready(node) => node.find_last_element(dom),
  178. _ => todo!("cannot handle nonstandard nodes"),
  179. }
  180. }
  181. }
  182. }
  183. }
  184. }
  185. /// Diff the two text nodes
  186. ///
  187. /// This just sets the text of the node if it's different.
  188. fn diff_vtext(
  189. &self,
  190. to: &mut impl WriteMutations,
  191. mount: &VNodeMount,
  192. idx: usize,
  193. left: &VText,
  194. right: &VText,
  195. ) {
  196. if left.value != right.value {
  197. let id = ElementId(mount.mounted_dynamic_nodes[idx]);
  198. to.set_node_text(&right.value, id);
  199. }
  200. }
  201. pub(crate) fn replace<'a>(
  202. &self,
  203. right: impl IntoIterator<Item = &'a VNode>,
  204. parent: Option<ElementRef>,
  205. dom: &mut VirtualDom,
  206. to: &mut impl WriteMutations,
  207. ) {
  208. let m = dom.create_children(to, right, parent);
  209. // TODO: Instead of *just* removing it, we can use the replace mutation
  210. let first_element = self.find_first_element(dom);
  211. to.insert_nodes_before(first_element, m);
  212. self.remove_node(dom, to, true)
  213. }
  214. pub(crate) fn remove_node(
  215. &self,
  216. dom: &mut VirtualDom,
  217. to: &mut impl WriteMutations,
  218. gen_muts: bool,
  219. ) {
  220. let mount = self.assert_mounted();
  221. // Clean up any attributes that have claimed a static node as dynamic for mount/unmounts
  222. // Will not generate mutations!
  223. self.reclaim_attributes(&mount, dom, to);
  224. // Remove the nested dynamic nodes
  225. // We don't generate mutations for these, as they will be removed by the parent (in the next line)
  226. // But we still need to make sure to reclaim them from the arena and drop their hooks, etc
  227. self.remove_nested_dyn_nodes(&mount, dom, to);
  228. // Clean up the roots, assuming we need to generate mutations for these
  229. // This is done last in order to preserve Node ID reclaim order (reclaim in reverse order of claim)
  230. self.reclaim_roots(&mount, dom, to, gen_muts);
  231. }
  232. fn reclaim_roots(
  233. &self,
  234. mount: &VNodeMount,
  235. dom: &mut VirtualDom,
  236. to: &mut impl WriteMutations,
  237. gen_muts: bool,
  238. ) {
  239. for (idx, node) in self.template.get().roots.iter().enumerate() {
  240. if let Some(id) = node.dynamic_id() {
  241. let dynamic_node = &self.dynamic_nodes[id];
  242. self.remove_dynamic_node(mount, dom, to, idx, dynamic_node, gen_muts);
  243. } else {
  244. let id = ElementId(mount.mounted_dynamic_nodes[idx]);
  245. if gen_muts {
  246. to.remove_node(id);
  247. }
  248. dom.reclaim(id);
  249. }
  250. }
  251. }
  252. fn remove_nested_dyn_nodes(
  253. &self,
  254. mount: &VNodeMount,
  255. dom: &mut VirtualDom,
  256. to: &mut impl WriteMutations,
  257. ) {
  258. let template = self.template.get();
  259. for (idx, dyn_node) in self.dynamic_nodes.iter().enumerate() {
  260. let path_len = template.node_paths.get(idx).map(|path| path.len());
  261. // Roots are cleaned up automatically above and nodes with a empty path are placeholders
  262. if let Some(2..) = path_len {
  263. self.remove_dynamic_node(mount, dom, to, idx, dyn_node, false)
  264. }
  265. }
  266. }
  267. fn remove_dynamic_node(
  268. &self,
  269. mount: &VNodeMount,
  270. dom: &mut VirtualDom,
  271. to: &mut impl WriteMutations,
  272. idx: usize,
  273. node: &DynamicNode,
  274. gen_muts: bool,
  275. ) {
  276. match node {
  277. Component(_comp) => {
  278. let scope_id = ScopeId(mount.mounted_dynamic_nodes[idx]);
  279. dom.remove_component_node(to, scope_id, gen_muts);
  280. }
  281. Text(_) | Placeholder(_) => {
  282. let id = ElementId(mount.mounted_dynamic_nodes[idx]);
  283. dom.remove_element_id(to, id, gen_muts)
  284. }
  285. Fragment(nodes) => nodes
  286. .iter()
  287. .for_each(|_node| self.remove_node(dom, to, gen_muts)),
  288. };
  289. }
  290. fn assert_mounted(&self) -> Ref<'_, VNodeMount> {
  291. Ref::map(self.mount.borrow(), |mount| {
  292. mount.as_ref().expect("to be mounted")
  293. })
  294. }
  295. fn assert_mounted_mut(&self) -> RefMut<'_, VNodeMount> {
  296. RefMut::map(self.mount.borrow_mut(), |mount| {
  297. mount.as_mut().expect("to be mounted")
  298. })
  299. }
  300. fn templates_are_different(&self, other: &VNode) -> bool {
  301. let self_node_name = self.template.get().name;
  302. let other_node_name = other.template.get().name;
  303. // we want to re-create the node if the template name is different by pointer even if the value is the same so that we can detect when hot reloading changes the template
  304. !std::ptr::eq(self_node_name, other_node_name)
  305. }
  306. pub(super) fn reclaim_attributes(
  307. &self,
  308. mount: &VNodeMount,
  309. dom: &mut VirtualDom,
  310. _to: &mut impl WriteMutations,
  311. ) {
  312. let id = None;
  313. for (idx, path) in self.template.get().attr_paths.iter().enumerate() {
  314. let _attr = &self.dynamic_attrs[idx];
  315. // We clean up the roots in the next step, so don't worry about them here
  316. if path.len() <= 1 {
  317. continue;
  318. }
  319. let next_id = mount.mounted_attributes[idx];
  320. // only reclaim the new element if it's different from the previous one
  321. if id != Some(next_id) {
  322. dom.reclaim(next_id);
  323. }
  324. }
  325. }
  326. pub(super) fn update_attribute(
  327. &self,
  328. mount: &VNodeMount,
  329. idx: usize,
  330. new_attr: &Attribute,
  331. to: &mut impl WriteMutations,
  332. ) {
  333. let name = &new_attr.name;
  334. let value = &new_attr.value;
  335. let id = mount.mounted_attributes[idx];
  336. to.set_attribute(name, new_attr.namespace, value, id);
  337. }
  338. /// Lightly diff the two templates, checking only their roots.
  339. ///
  340. /// The goal here is to preserve any existing component state that might exist. This is to preserve some React-like
  341. /// behavior where the component state is preserved when the component is re-rendered.
  342. ///
  343. /// This is implemented by iterating each root, checking if the component is the same, if it is, then diff it.
  344. ///
  345. /// We then pass the new template through "create" which should be smart enough to skip roots.
  346. ///
  347. /// Currently, we only handle the case where the roots are the same component list. If there's any sort of deviation,
  348. /// IE more nodes, less nodes, different nodes, or expressions, then we just replace the whole thing.
  349. ///
  350. /// This is mostly implemented to help solve the issue where the same component is rendered under two different
  351. /// conditions:
  352. ///
  353. /// ```rust, ignore
  354. /// if enabled {
  355. /// rsx!{ Component { enabled_sign: "abc" } }
  356. /// } else {
  357. /// rsx!{ Component { enabled_sign: "xyz" } }
  358. /// }
  359. /// ```
  360. ///
  361. /// However, we should not that it's explicit in the docs that this is not a guarantee. If you need to preserve state,
  362. /// then you should be passing in separate props instead.
  363. ///
  364. /// ```rust, ignore
  365. /// let props = if enabled {
  366. /// ComponentProps { enabled_sign: "abc" }
  367. /// } else {
  368. /// ComponentProps { enabled_sign: "xyz" }
  369. /// };
  370. ///
  371. /// rsx! {
  372. /// Component { ..props }
  373. /// }
  374. /// ```
  375. pub(crate) fn light_diff_templates(
  376. &self,
  377. new: &VNode,
  378. dom: &mut VirtualDom,
  379. to: &mut impl WriteMutations,
  380. ) {
  381. let parent = new.parent();
  382. match matching_components(self, new) {
  383. None => self.replace([new], parent, dom, to),
  384. Some(components) => {
  385. let mut mount = self.assert_mounted_mut();
  386. for (idx, (old_component, new_component)) in components.into_iter().enumerate() {
  387. let scope_id = ScopeId(self.assert_mounted().mounted_dynamic_nodes[idx]);
  388. self.diff_vcomponent(
  389. &mut mount,
  390. idx,
  391. old_component,
  392. new_component,
  393. scope_id,
  394. parent.clone(),
  395. dom,
  396. to,
  397. )
  398. }
  399. }
  400. }
  401. }
  402. /// Create this template and write its mutations
  403. pub(crate) fn create(
  404. &self,
  405. dom: &mut VirtualDom,
  406. to: &mut impl WriteMutations,
  407. parent: Option<ElementRef>,
  408. ) -> usize {
  409. // check for a overridden template
  410. #[cfg(debug_assertions)]
  411. {
  412. let template = self.template.get();
  413. let (path, byte_index) = template.name.rsplit_once(':').unwrap();
  414. if let Some(new_template) = dom
  415. .templates
  416. .get(path)
  417. .and_then(|map| map.get(&byte_index.parse().unwrap()))
  418. {
  419. self.template.set(*new_template);
  420. }
  421. };
  422. let template = self.template.get();
  423. // The best renderers will have templates pre-hydrated and registered
  424. // Just in case, let's create the template using instructions anyways
  425. dom.register_template(to, template);
  426. // Walk the roots, creating nodes and assigning IDs
  427. // nodes in an iterator of ((dynamic_node_index, sorted_index), path)
  428. // todo: adjust dynamic nodes to be in the order of roots and then leaves (ie BFS)
  429. #[cfg(not(debug_assertions))]
  430. let (mut attrs, mut nodes) = (
  431. template.attr_paths.iter().copied().enumerate().peekable(),
  432. template
  433. .node_paths
  434. .iter()
  435. .copied()
  436. .enumerate()
  437. .map(|(i, path)| ((i, i), path))
  438. .peekable(),
  439. );
  440. // If this is a debug build, we need to check that the paths are in the correct order because hot reloading can cause scrambled states
  441. #[cfg(debug_assertions)]
  442. let (attrs_sorted, nodes_sorted) =
  443. { (sort_bfs(template.attr_paths), sort_bfs(template.node_paths)) };
  444. #[cfg(debug_assertions)]
  445. let (mut attrs, mut nodes) = {
  446. (
  447. attrs_sorted.into_iter().peekable(),
  448. nodes_sorted
  449. .iter()
  450. .copied()
  451. .enumerate()
  452. .map(|(i, (id, path))| ((id, i), path))
  453. .peekable(),
  454. )
  455. };
  456. let mut node = self.mount.borrow_mut();
  457. // Initialize the mount information for this template
  458. *node = Some(VNodeMount {
  459. parent,
  460. root_ids: vec![ElementId(0); template.roots.len()].into_boxed_slice(),
  461. mounted_attributes: vec![ElementId(0); template.attr_paths.len()].into_boxed_slice(),
  462. mounted_dynamic_nodes: vec![0; template.node_paths.len()].into_boxed_slice(),
  463. });
  464. let mount = node.as_mut().unwrap();
  465. template
  466. .roots
  467. .iter()
  468. .enumerate()
  469. .map(|(idx, root)| match root {
  470. DynamicText { id } | Dynamic { id } => {
  471. nodes.next().unwrap();
  472. self.write_dynamic_root(mount, *id, dom, to)
  473. }
  474. Element { .. } => {
  475. #[cfg(not(debug_assertions))]
  476. let id =
  477. self.write_element_root(mount, idx, &mut attrs, &mut nodes, &[], dom, to);
  478. #[cfg(debug_assertions)]
  479. let id = self.write_element_root(
  480. mount,
  481. idx,
  482. &mut attrs,
  483. &mut nodes,
  484. &nodes_sorted,
  485. dom,
  486. to,
  487. );
  488. id
  489. }
  490. TemplateNode::Text { .. } => self.write_static_text_root(mount, idx, dom, to),
  491. })
  492. .sum()
  493. }
  494. }
  495. impl VNode {
  496. fn write_static_text_root(
  497. &self,
  498. mount: &mut VNodeMount,
  499. idx: usize,
  500. dom: &mut VirtualDom,
  501. to: &mut impl WriteMutations,
  502. ) -> usize {
  503. // Simply just load the template root, no modifications needed
  504. self.load_template_root(mount, idx, dom, to);
  505. // Text producs just one node on the stack
  506. 1
  507. }
  508. fn write_dynamic_root(
  509. &self,
  510. mount: &mut VNodeMount,
  511. idx: usize,
  512. dom: &mut VirtualDom,
  513. to: &mut impl WriteMutations,
  514. ) -> usize {
  515. use DynamicNode::*;
  516. match &self.dynamic_nodes[idx] {
  517. Component(component) => {
  518. let parent = Some(ElementRef {
  519. path: ElementPath {
  520. path: self.template.get().node_paths[idx],
  521. },
  522. element: self.clone_with_parent(),
  523. });
  524. self.create_component_node(mount, idx, component, parent, dom, to)
  525. }
  526. Fragment(frag) => {
  527. let parent = Some(ElementRef {
  528. path: ElementPath {
  529. path: self.template.get().node_paths[idx],
  530. },
  531. element: self.clone_with_parent(),
  532. });
  533. dom.create_children(to, frag, parent)
  534. }
  535. Placeholder(_) => {
  536. let id = mount.mount_node(idx, dom);
  537. to.create_placeholder(id);
  538. 1
  539. }
  540. Text(VText { value }) => {
  541. let id = mount.mount_node(idx, dom);
  542. to.create_text_node(value, id);
  543. 1
  544. }
  545. }
  546. }
  547. /// We write all the descendent data for this element
  548. ///
  549. /// Elements can contain other nodes - and those nodes can be dynamic or static
  550. ///
  551. /// We want to make sure we write these nodes while on top of the root
  552. fn write_element_root(
  553. &self,
  554. mount: &mut VNodeMount,
  555. root_idx: usize,
  556. dynamic_attrs: &mut Peekable<impl Iterator<Item = (usize, &'static [u8])>>,
  557. dynamic_nodes_iter: &mut Peekable<impl Iterator<Item = ((usize, usize), &'static [u8])>>,
  558. dynamic_nodes: &[(usize, &'static [u8])],
  559. dom: &mut VirtualDom,
  560. to: &mut impl WriteMutations,
  561. ) -> usize {
  562. // Load the template root and get the ID for the node on the stack
  563. let root_on_stack = self.load_template_root(mount, root_idx, dom, to);
  564. // Write all the attributes below this root
  565. self.write_attrs_on_root(mount, dynamic_attrs, root_idx as u8, root_on_stack, dom, to);
  566. // Load in all of the placeholder or dynamic content under this root too
  567. self.load_placeholders(
  568. mount,
  569. dynamic_nodes_iter,
  570. dynamic_nodes,
  571. root_idx as u8,
  572. dom,
  573. to,
  574. );
  575. 1
  576. }
  577. /// Load all of the placeholder nodes for descendents of this root node
  578. ///
  579. /// ```rust, ignore
  580. /// rsx! {
  581. /// div {
  582. /// // This is a placeholder
  583. /// some_value,
  584. ///
  585. /// // Load this too
  586. /// "{some_text}"
  587. /// }
  588. /// }
  589. /// ```
  590. #[allow(unused)]
  591. fn load_placeholders(
  592. &self,
  593. mount: &mut VNodeMount,
  594. dynamic_nodes_iter: &mut Peekable<impl Iterator<Item = ((usize, usize), &'static [u8])>>,
  595. dynamic_nodes: &[(usize, &'static [u8])],
  596. root_idx: u8,
  597. dom: &mut VirtualDom,
  598. to: &mut impl WriteMutations,
  599. ) {
  600. let (start, end) = match collect_dyn_node_range(dynamic_nodes_iter, root_idx) {
  601. Some((a, b)) => (a, b),
  602. None => return,
  603. };
  604. // If hot reloading is enabled, we need to map the sorted index to the original index of the dynamic node. If it is disabled, we can just use the sorted index
  605. #[cfg(not(debug_assertions))]
  606. let reversed_iter = (start..=end).rev();
  607. #[cfg(debug_assertions)]
  608. let reversed_iter = (start..=end)
  609. .rev()
  610. .map(|sorted_index| dynamic_nodes[sorted_index].0);
  611. for idx in reversed_iter {
  612. let m = self.create_dynamic_node(mount, idx, dom, to);
  613. if m > 0 {
  614. // The path is one shorter because the top node is the root
  615. let path = &self.template.get().node_paths[idx][1..];
  616. to.replace_placeholder_with_nodes(path, m);
  617. }
  618. }
  619. }
  620. fn write_attrs_on_root(
  621. &self,
  622. mount: &mut VNodeMount,
  623. attrs: &mut Peekable<impl Iterator<Item = (usize, &'static [u8])>>,
  624. root_idx: u8,
  625. root: ElementId,
  626. dom: &mut VirtualDom,
  627. to: &mut impl WriteMutations,
  628. ) {
  629. while let Some((mut attr_id, path)) =
  630. attrs.next_if(|(_, p)| p.first().copied() == Some(root_idx))
  631. {
  632. let id = self.assign_static_node_as_dynamic(path, root, dom, to);
  633. loop {
  634. self.write_attribute(mount, attr_id, id, dom, to);
  635. // Only push the dynamic attributes forward if they match the current path (same element)
  636. match attrs.next_if(|(_, p)| *p == path) {
  637. Some((next_attr_id, _)) => attr_id = next_attr_id,
  638. None => break,
  639. }
  640. }
  641. }
  642. }
  643. fn write_attribute(
  644. &self,
  645. mount: &mut VNodeMount,
  646. idx: usize,
  647. id: ElementId,
  648. dom: &mut VirtualDom,
  649. to: &mut impl WriteMutations,
  650. ) {
  651. // Make sure we set the attribute's associated id
  652. mount.mounted_attributes[idx] = id;
  653. let attribute = &self.dynamic_attrs[idx];
  654. match &attribute.value {
  655. AttributeValue::Listener(_) => {
  656. // If this is a listener, we need to create an element reference for it so that when we receive an event, we can find the element
  657. let path = &self.template.get().attr_paths[idx];
  658. let element_ref = ElementRef {
  659. path: ElementPath { path },
  660. element: self.clone_with_parent(),
  661. };
  662. dom.elements[id.0] = Some(element_ref);
  663. to.create_event_listener(&attribute.name[2..], id);
  664. }
  665. _ => {
  666. to.set_attribute(attribute.name, attribute.namespace, &attribute.value, id);
  667. }
  668. }
  669. }
  670. fn load_template_root(
  671. &self,
  672. mount: &mut VNodeMount,
  673. root_idx: usize,
  674. dom: &mut VirtualDom,
  675. to: &mut impl WriteMutations,
  676. ) -> ElementId {
  677. // Get an ID for this root since it's a real root
  678. let this_id = dom.next_element();
  679. mount.root_ids[root_idx] = this_id;
  680. to.load_template(self.template.get().name, root_idx, this_id);
  681. this_id
  682. }
  683. /// We have some dynamic attributes attached to a some node
  684. ///
  685. /// That node needs to be loaded at runtime, so we need to give it an ID
  686. ///
  687. /// If the node in question is on the stack, we just return that ID
  688. ///
  689. /// If the node is not on the stack, we create a new ID for it and assign it
  690. fn assign_static_node_as_dynamic(
  691. &self,
  692. path: &'static [u8],
  693. this_id: ElementId,
  694. dom: &mut VirtualDom,
  695. to: &mut impl WriteMutations,
  696. ) -> ElementId {
  697. if path.len() == 1 {
  698. return this_id;
  699. }
  700. // if attribute is on a root node, then we've already created the element
  701. // Else, it's deep in the template and we should create a new id for it
  702. let id = dom.next_element();
  703. to.assign_node_id(&path[1..], id);
  704. id
  705. }
  706. pub(crate) fn create_dynamic_node(
  707. &self,
  708. mount: &mut VNodeMount,
  709. index: usize,
  710. dom: &mut VirtualDom,
  711. to: &mut impl WriteMutations,
  712. ) -> usize {
  713. use DynamicNode::*;
  714. let node = &self.dynamic_nodes[index];
  715. match node {
  716. Text(text) => self.create_dynamic_text(mount, index, text, dom, to),
  717. Placeholder(_) => self.create_placeholder(mount, index, dom, to),
  718. Component(component) => {
  719. let parent = Some(ElementRef {
  720. path: ElementPath {
  721. path: self.template.get().node_paths[index],
  722. },
  723. element: self.clone_with_parent(),
  724. });
  725. self.create_component_node(mount, index, component, parent, dom, to)
  726. }
  727. Fragment(frag) => {
  728. let parent = Some(ElementRef {
  729. path: ElementPath {
  730. path: self.template.get().node_paths[index],
  731. },
  732. element: self.clone_with_parent(),
  733. });
  734. dom.create_children(to, frag, parent)
  735. }
  736. }
  737. }
  738. /// Mount a root node and return its ID and the path to the node
  739. fn mount_dynamic_node_with_path(
  740. &self,
  741. mount: &mut VNodeMount,
  742. idx: usize,
  743. dom: &mut VirtualDom,
  744. ) -> (ElementId, &'static [u8]) {
  745. // Add the mutation to the list
  746. let path = self.template.get().node_paths[idx];
  747. // Allocate a dynamic element reference for this text node
  748. let new_id = mount.mount_node(idx, dom);
  749. (new_id, &path[1..])
  750. }
  751. fn create_dynamic_text(
  752. &self,
  753. mount: &mut VNodeMount,
  754. idx: usize,
  755. text: &VText,
  756. dom: &mut VirtualDom,
  757. to: &mut impl WriteMutations,
  758. ) -> usize {
  759. let (new_id, path) = self.mount_dynamic_node_with_path(mount, idx, dom);
  760. // Hydrate the text node
  761. to.hydrate_text_node(path, &text.value, new_id);
  762. // Since we're hydrating an existing node, we don't create any new nodes
  763. 0
  764. }
  765. pub(crate) fn create_placeholder(
  766. &self,
  767. mount: &mut VNodeMount,
  768. idx: usize,
  769. dom: &mut VirtualDom,
  770. to: &mut impl WriteMutations,
  771. ) -> usize {
  772. let (id, path) = self.mount_dynamic_node_with_path(mount, idx, dom);
  773. // Assign the ID to the existing node in the template
  774. to.assign_node_id(path, id);
  775. // Since the placeholder is already in the DOM, we don't create any new nodes
  776. 0
  777. }
  778. }
  779. impl VNodeMount {
  780. fn mount_node(&mut self, node_index: usize, dom: &mut VirtualDom) -> ElementId {
  781. let id = dom.next_element();
  782. self.mounted_dynamic_nodes[node_index] = id.0;
  783. id
  784. }
  785. }
  786. fn collect_dyn_node_range(
  787. dynamic_nodes: &mut Peekable<impl Iterator<Item = ((usize, usize), &'static [u8])>>,
  788. root_idx: u8,
  789. ) -> Option<(usize, usize)> {
  790. let start = match dynamic_nodes.peek() {
  791. Some(((_, idx), [first, ..])) if *first == root_idx => *idx,
  792. _ => return None,
  793. };
  794. let mut end = start;
  795. while let Some(((_, idx), p)) =
  796. dynamic_nodes.next_if(|(_, p)| matches!(p, [idx, ..] if *idx == root_idx))
  797. {
  798. if p.len() == 1 {
  799. continue;
  800. }
  801. end = idx;
  802. }
  803. Some((start, end))
  804. }
  805. fn matching_components<'a>(
  806. left: &'a VNode,
  807. right: &'a VNode,
  808. ) -> Option<Vec<(&'a VComponent, &'a VComponent)>> {
  809. let left_node = left.template.get();
  810. let right_node = right.template.get();
  811. if left_node.roots.len() != right_node.roots.len() {
  812. return None;
  813. }
  814. // run through the components, ensuring they're the same
  815. left_node
  816. .roots
  817. .iter()
  818. .zip(right_node.roots.iter())
  819. .map(|(l, r)| {
  820. let (l, r) = match (l, r) {
  821. (TemplateNode::Dynamic { id: l }, TemplateNode::Dynamic { id: r }) => (l, r),
  822. _ => return None,
  823. };
  824. let (l, r) = match (&left.dynamic_nodes[*l], &right.dynamic_nodes[*r]) {
  825. (Component(l), Component(r)) => (l, r),
  826. _ => return None,
  827. };
  828. Some((l, r))
  829. })
  830. .collect()
  831. }
  832. #[cfg(debug_assertions)]
  833. fn sort_bfs(paths: &[&'static [u8]]) -> Vec<(usize, &'static [u8])> {
  834. let mut with_indecies = paths.iter().copied().enumerate().collect::<Vec<_>>();
  835. with_indecies.sort_unstable_by(|(_, a), (_, b)| {
  836. let mut a = a.iter();
  837. let mut b = b.iter();
  838. loop {
  839. match (a.next(), b.next()) {
  840. (Some(a), Some(b)) => {
  841. if a != b {
  842. return a.cmp(b);
  843. }
  844. }
  845. // The shorter path goes first
  846. (None, Some(_)) => return std::cmp::Ordering::Less,
  847. (Some(_), None) => return std::cmp::Ordering::Greater,
  848. (None, None) => return std::cmp::Ordering::Equal,
  849. }
  850. }
  851. });
  852. with_indecies
  853. }
  854. #[test]
  855. #[cfg(debug_assertions)]
  856. fn sorting() {
  857. let r: [(usize, &[u8]); 5] = [
  858. (0, &[0, 1]),
  859. (1, &[0, 2]),
  860. (2, &[1, 0]),
  861. (3, &[1, 0, 1]),
  862. (4, &[1, 2]),
  863. ];
  864. assert_eq!(
  865. sort_bfs(&[&[0, 1,], &[0, 2,], &[1, 0,], &[1, 0, 1,], &[1, 2,],]),
  866. r
  867. );
  868. let r: [(usize, &[u8]); 6] = [
  869. (0, &[0]),
  870. (1, &[0, 1]),
  871. (2, &[0, 1, 2]),
  872. (3, &[1]),
  873. (4, &[1, 2]),
  874. (5, &[2]),
  875. ];
  876. assert_eq!(
  877. sort_bfs(&[&[0], &[0, 1], &[0, 1, 2], &[1], &[1, 2], &[2],]),
  878. r
  879. );
  880. }