node.rs 35 KB

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