node.rs 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  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[..nodes.len() - 1] {
  274. node.remove_node(dom, to, None, gen_muts)
  275. }
  276. if let Some(last_node) = nodes.last() {
  277. last_node.remove_node(dom, to, replace_with, gen_muts)
  278. }
  279. }
  280. };
  281. }
  282. fn templates_are_different(&self, other: &VNode) -> bool {
  283. let self_node_name = self.template.get().name;
  284. let other_node_name = other.template.get().name;
  285. // 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
  286. !std::ptr::eq(self_node_name, other_node_name)
  287. }
  288. pub(super) fn reclaim_attributes(
  289. &self,
  290. mount: MountId,
  291. dom: &mut VirtualDom,
  292. _to: &mut impl WriteMutations,
  293. ) {
  294. let mut id = None;
  295. for (idx, path) in self.template.get().attr_paths.iter().enumerate() {
  296. let _attr = &self.dynamic_attrs[idx];
  297. // We clean up the roots in the next step, so don't worry about them here
  298. if path.len() <= 1 {
  299. continue;
  300. }
  301. let next_id = dom.mounts[mount.0].mounted_attributes[idx];
  302. // only reclaim the new element if it's different from the previous one
  303. if id != Some(next_id) {
  304. dom.reclaim(next_id);
  305. id = Some(next_id);
  306. }
  307. }
  308. }
  309. pub(super) fn diff_attributes(
  310. &self,
  311. new: &VNode,
  312. dom: &mut VirtualDom,
  313. to: &mut impl WriteMutations,
  314. ) {
  315. let mount_id = self.mount.get();
  316. for (idx, (old_attrs, new_attrs)) in self
  317. .dynamic_attrs
  318. .iter()
  319. .zip(new.dynamic_attrs.iter())
  320. .enumerate()
  321. {
  322. let mut old_attributes_iter = old_attrs.iter().peekable();
  323. let mut new_attributes_iter = new_attrs.iter().peekable();
  324. let attribute_id = dom.mounts[mount_id.0].mounted_attributes[idx];
  325. let path = self.template.get().attr_paths[idx];
  326. loop {
  327. match (old_attributes_iter.peek(), new_attributes_iter.peek()) {
  328. (Some(old_attribute), Some(new_attribute)) => {
  329. // check which name is greater
  330. match old_attribute.name.cmp(new_attribute.name) {
  331. // The two attributes are the same, so diff them
  332. std::cmp::Ordering::Equal => {
  333. let old = old_attributes_iter.next().unwrap();
  334. let new = new_attributes_iter.next().unwrap();
  335. if old.value != new.value {
  336. self.write_attribute(
  337. path,
  338. new,
  339. attribute_id,
  340. mount_id,
  341. dom,
  342. to,
  343. );
  344. }
  345. }
  346. // In a sorted list, if the old attribute name is first, then the new attribute is missing
  347. std::cmp::Ordering::Less => {
  348. let old = old_attributes_iter.next().unwrap();
  349. self.remove_attribute(old, attribute_id, to)
  350. }
  351. // In a sorted list, if the new attribute name is first, then the old attribute is missing
  352. std::cmp::Ordering::Greater => {
  353. let new = new_attributes_iter.next().unwrap();
  354. self.write_attribute(path, new, attribute_id, mount_id, dom, to);
  355. }
  356. }
  357. }
  358. (Some(_), None) => {
  359. let left = old_attributes_iter.next().unwrap();
  360. self.remove_attribute(left, attribute_id, to)
  361. }
  362. (None, Some(_)) => {
  363. let right = new_attributes_iter.next().unwrap();
  364. self.write_attribute(path, right, attribute_id, mount_id, dom, to)
  365. }
  366. (None, None) => break,
  367. }
  368. }
  369. }
  370. }
  371. fn remove_attribute(&self, attribute: &Attribute, id: ElementId, to: &mut impl WriteMutations) {
  372. match &attribute.value {
  373. AttributeValue::Listener(_) => {
  374. to.remove_event_listener(&attribute.name[2..], id);
  375. }
  376. _ => {
  377. to.set_attribute(
  378. attribute.name,
  379. attribute.namespace,
  380. &AttributeValue::None,
  381. id,
  382. );
  383. }
  384. }
  385. }
  386. fn write_attribute(
  387. &self,
  388. path: &'static [u8],
  389. attribute: &Attribute,
  390. id: ElementId,
  391. mount: MountId,
  392. dom: &mut VirtualDom,
  393. to: &mut impl WriteMutations,
  394. ) {
  395. match &attribute.value {
  396. AttributeValue::Listener(_) => {
  397. let element_ref = ElementRef {
  398. path: ElementPath { path },
  399. mount,
  400. };
  401. dom.elements[id.0] = Some(element_ref);
  402. to.create_event_listener(&attribute.name[2..], id);
  403. }
  404. _ => {
  405. to.set_attribute(attribute.name, attribute.namespace, &attribute.value, id);
  406. }
  407. }
  408. }
  409. /// Lightly diff the two templates, checking only their roots.
  410. ///
  411. /// The goal here is to preserve any existing component state that might exist. This is to preserve some React-like
  412. /// behavior where the component state is preserved when the component is re-rendered.
  413. ///
  414. /// This is implemented by iterating each root, checking if the component is the same, if it is, then diff it.
  415. ///
  416. /// We then pass the new template through "create" which should be smart enough to skip roots.
  417. ///
  418. /// Currently, we only handle the case where the roots are the same component list. If there's any sort of deviation,
  419. /// IE more nodes, less nodes, different nodes, or expressions, then we just replace the whole thing.
  420. ///
  421. /// This is mostly implemented to help solve the issue where the same component is rendered under two different
  422. /// conditions:
  423. ///
  424. /// ```rust, ignore
  425. /// if enabled {
  426. /// rsx!{ Component { enabled_sign: "abc" } }
  427. /// } else {
  428. /// rsx!{ Component { enabled_sign: "xyz" } }
  429. /// }
  430. /// ```
  431. ///
  432. /// However, we should not that it's explicit in the docs that this is not a guarantee. If you need to preserve state,
  433. /// then you should be passing in separate props instead.
  434. ///
  435. /// ```rust, ignore
  436. /// let props = if enabled {
  437. /// ComponentProps { enabled_sign: "abc" }
  438. /// } else {
  439. /// ComponentProps { enabled_sign: "xyz" }
  440. /// };
  441. ///
  442. /// rsx! {
  443. /// Component { ..props }
  444. /// }
  445. /// ```
  446. pub(crate) fn light_diff_templates(
  447. &self,
  448. new: &VNode,
  449. dom: &mut VirtualDom,
  450. to: &mut impl WriteMutations,
  451. ) {
  452. let mount_id = self.mount.get();
  453. let mount = &dom.mounts[mount_id.0];
  454. let parent = mount.parent;
  455. match matching_components(self, new) {
  456. None => self.replace([new], parent, dom, to),
  457. Some(components) => {
  458. self.move_mount_to(new, dom);
  459. for (idx, (old_component, new_component)) in components.into_iter().enumerate() {
  460. let mount = &dom.mounts[mount_id.0];
  461. let scope_id = ScopeId(mount.mounted_dynamic_nodes[idx]);
  462. self.diff_vcomponent(
  463. mount_id,
  464. idx,
  465. new_component,
  466. old_component,
  467. scope_id,
  468. parent,
  469. dom,
  470. to,
  471. )
  472. }
  473. }
  474. }
  475. }
  476. /// Create this template and write its mutations
  477. pub(crate) fn create(
  478. &self,
  479. dom: &mut VirtualDom,
  480. to: &mut impl WriteMutations,
  481. parent: Option<ElementRef>,
  482. ) -> usize {
  483. // check for a overridden template
  484. #[cfg(debug_assertions)]
  485. {
  486. let template = self.template.get();
  487. let (path, byte_index) = template.name.rsplit_once(':').unwrap();
  488. if let Some(new_template) = dom
  489. .templates
  490. .get(path)
  491. .and_then(|map| map.get(&byte_index.parse().unwrap()))
  492. {
  493. self.template.set(*new_template);
  494. }
  495. };
  496. let template = self.template.get();
  497. // The best renderers will have templates pre-hydrated and registered
  498. // Just in case, let's create the template using instructions anyways
  499. dom.register_template(to, template);
  500. // Initialize the mount information for this template
  501. let entry = dom.mounts.vacant_entry();
  502. let mount = MountId(entry.key());
  503. self.mount.set(mount);
  504. tracing::trace!(?self, ?mount, "creating template");
  505. entry.insert(VNodeMount {
  506. node: self.clone_mounted(),
  507. parent,
  508. root_ids: vec![ElementId(0); template.roots.len()].into_boxed_slice(),
  509. mounted_attributes: vec![ElementId(0); template.attr_paths.len()].into_boxed_slice(),
  510. mounted_dynamic_nodes: vec![0; template.node_paths.len()].into_boxed_slice(),
  511. });
  512. // Walk the roots, creating nodes and assigning IDs
  513. // nodes in an iterator of ((dynamic_node_index, sorted_index), path)
  514. // todo: adjust dynamic nodes to be in the order of roots and then leaves (ie BFS)
  515. #[cfg(not(debug_assertions))]
  516. let (mut attrs, mut nodes) = (
  517. template.attr_paths.iter().copied().enumerate().peekable(),
  518. template
  519. .node_paths
  520. .iter()
  521. .copied()
  522. .enumerate()
  523. .map(|(i, path)| ((i, i), path))
  524. .peekable(),
  525. );
  526. // 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
  527. #[cfg(debug_assertions)]
  528. let (attrs_sorted, nodes_sorted) =
  529. { (sort_bfs(template.attr_paths), sort_bfs(template.node_paths)) };
  530. #[cfg(debug_assertions)]
  531. let (mut attrs, mut nodes) = {
  532. (
  533. attrs_sorted.into_iter().peekable(),
  534. nodes_sorted
  535. .iter()
  536. .copied()
  537. .enumerate()
  538. .map(|(i, (id, path))| ((id, i), path))
  539. .peekable(),
  540. )
  541. };
  542. template
  543. .roots
  544. .iter()
  545. .enumerate()
  546. .map(|(idx, root)| match root {
  547. DynamicText { id } | Dynamic { id } => {
  548. nodes.next().unwrap();
  549. self.write_dynamic_root(mount, *id, dom, to)
  550. }
  551. Element { .. } => {
  552. #[cfg(not(debug_assertions))]
  553. let id =
  554. self.write_element_root(mount, idx, &mut attrs, &mut nodes, &[], dom, to);
  555. #[cfg(debug_assertions)]
  556. let id = self.write_element_root(
  557. mount,
  558. idx,
  559. &mut attrs,
  560. &mut nodes,
  561. &nodes_sorted,
  562. dom,
  563. to,
  564. );
  565. id
  566. }
  567. TemplateNode::Text { .. } => self.write_static_text_root(mount, idx, dom, to),
  568. })
  569. .sum()
  570. }
  571. }
  572. impl VNode {
  573. fn write_static_text_root(
  574. &self,
  575. mount: MountId,
  576. idx: usize,
  577. dom: &mut VirtualDom,
  578. to: &mut impl WriteMutations,
  579. ) -> usize {
  580. // Simply just load the template root, no modifications needed
  581. self.load_template_root(mount, idx, dom, to);
  582. // Text produces just one node on the stack
  583. 1
  584. }
  585. fn write_dynamic_root(
  586. &self,
  587. mount: MountId,
  588. idx: usize,
  589. dom: &mut VirtualDom,
  590. to: &mut impl WriteMutations,
  591. ) -> usize {
  592. use DynamicNode::*;
  593. match &self.dynamic_nodes[idx] {
  594. Component(component) => {
  595. let parent = Some(ElementRef {
  596. path: ElementPath {
  597. path: self.template.get().node_paths[idx],
  598. },
  599. mount,
  600. });
  601. self.create_component_node(mount, idx, component, parent, dom, to)
  602. }
  603. Fragment(frag) => {
  604. let parent = Some(ElementRef {
  605. path: ElementPath {
  606. path: self.template.get().node_paths[idx],
  607. },
  608. mount,
  609. });
  610. dom.create_children(to, frag, parent)
  611. }
  612. Placeholder(_) => {
  613. let id = mount.mount_node(idx, dom);
  614. to.create_placeholder(id);
  615. 1
  616. }
  617. Text(VText { value }) => {
  618. let id = mount.mount_node(idx, dom);
  619. to.create_text_node(value, id);
  620. 1
  621. }
  622. }
  623. }
  624. /// We write all the descendent data for this element
  625. ///
  626. /// Elements can contain other nodes - and those nodes can be dynamic or static
  627. ///
  628. /// We want to make sure we write these nodes while on top of the root
  629. fn write_element_root(
  630. &self,
  631. mount: MountId,
  632. root_idx: usize,
  633. dynamic_attrs: &mut Peekable<impl Iterator<Item = (usize, &'static [u8])>>,
  634. dynamic_nodes_iter: &mut Peekable<impl Iterator<Item = ((usize, usize), &'static [u8])>>,
  635. dynamic_nodes: &[(usize, &'static [u8])],
  636. dom: &mut VirtualDom,
  637. to: &mut impl WriteMutations,
  638. ) -> usize {
  639. // Load the template root and get the ID for the node on the stack
  640. let root_on_stack = self.load_template_root(mount, root_idx, dom, to);
  641. // Write all the attributes below this root
  642. self.write_attrs_on_root(mount, dynamic_attrs, root_idx as u8, root_on_stack, dom, to);
  643. // Load in all of the placeholder or dynamic content under this root too
  644. self.load_placeholders(
  645. mount,
  646. dynamic_nodes_iter,
  647. dynamic_nodes,
  648. root_idx as u8,
  649. dom,
  650. to,
  651. );
  652. 1
  653. }
  654. /// Load all of the placeholder nodes for descendents of this root node
  655. ///
  656. /// ```rust, ignore
  657. /// rsx! {
  658. /// div {
  659. /// // This is a placeholder
  660. /// some_value,
  661. ///
  662. /// // Load this too
  663. /// "{some_text}"
  664. /// }
  665. /// }
  666. /// ```
  667. #[allow(unused)]
  668. fn load_placeholders(
  669. &self,
  670. mount: MountId,
  671. dynamic_nodes_iter: &mut Peekable<impl Iterator<Item = ((usize, usize), &'static [u8])>>,
  672. dynamic_nodes: &[(usize, &'static [u8])],
  673. root_idx: u8,
  674. dom: &mut VirtualDom,
  675. to: &mut impl WriteMutations,
  676. ) {
  677. let (start, end) = match collect_dyn_node_range(dynamic_nodes_iter, root_idx) {
  678. Some((a, b)) => (a, b),
  679. None => return,
  680. };
  681. // 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
  682. #[cfg(not(debug_assertions))]
  683. let reversed_iter = (start..=end).rev();
  684. #[cfg(debug_assertions)]
  685. let reversed_iter = (start..=end)
  686. .rev()
  687. .map(|sorted_index| dynamic_nodes[sorted_index].0);
  688. for idx in reversed_iter {
  689. let m = self.create_dynamic_node(mount, idx, dom, to);
  690. if m > 0 {
  691. // The path is one shorter because the top node is the root
  692. let path = &self.template.get().node_paths[idx][1..];
  693. to.replace_placeholder_with_nodes(path, m);
  694. }
  695. }
  696. }
  697. fn write_attrs_on_root(
  698. &self,
  699. mount: MountId,
  700. attrs: &mut Peekable<impl Iterator<Item = (usize, &'static [u8])>>,
  701. root_idx: u8,
  702. root: ElementId,
  703. dom: &mut VirtualDom,
  704. to: &mut impl WriteMutations,
  705. ) {
  706. while let Some((mut attr_id, path)) =
  707. attrs.next_if(|(_, p)| p.first().copied() == Some(root_idx))
  708. {
  709. let id = self.assign_static_node_as_dynamic(path, root, dom, to);
  710. loop {
  711. for attr in &*self.dynamic_attrs[attr_id] {
  712. self.write_attribute(path, attr, id, mount, dom, to);
  713. dom.mounts[mount.0].mounted_attributes[attr_id] = id;
  714. }
  715. // Only push the dynamic attributes forward if they match the current path (same element)
  716. match attrs.next_if(|(_, p)| *p == path) {
  717. Some((next_attr_id, _)) => attr_id = next_attr_id,
  718. None => break,
  719. }
  720. }
  721. }
  722. }
  723. fn load_template_root(
  724. &self,
  725. mount: MountId,
  726. root_idx: usize,
  727. dom: &mut VirtualDom,
  728. to: &mut impl WriteMutations,
  729. ) -> ElementId {
  730. // Get an ID for this root since it's a real root
  731. let this_id = dom.next_element();
  732. dom.mounts[mount.0].root_ids[root_idx] = this_id;
  733. to.load_template(self.template.get().name, root_idx, this_id);
  734. this_id
  735. }
  736. /// We have some dynamic attributes attached to a some node
  737. ///
  738. /// That node needs to be loaded at runtime, so we need to give it an ID
  739. ///
  740. /// If the node in question is on the stack, we just return that ID
  741. ///
  742. /// If the node is not on the stack, we create a new ID for it and assign it
  743. fn assign_static_node_as_dynamic(
  744. &self,
  745. path: &'static [u8],
  746. this_id: ElementId,
  747. dom: &mut VirtualDom,
  748. to: &mut impl WriteMutations,
  749. ) -> ElementId {
  750. if path.len() == 1 {
  751. return this_id;
  752. }
  753. // if attribute is on a root node, then we've already created the element
  754. // Else, it's deep in the template and we should create a new id for it
  755. let id = dom.next_element();
  756. to.assign_node_id(&path[1..], id);
  757. id
  758. }
  759. pub(crate) fn create_dynamic_node(
  760. &self,
  761. mount: MountId,
  762. index: usize,
  763. dom: &mut VirtualDom,
  764. to: &mut impl WriteMutations,
  765. ) -> usize {
  766. use DynamicNode::*;
  767. let node = &self.dynamic_nodes[index];
  768. match node {
  769. Text(text) => self.create_dynamic_text(mount, index, text, dom, to),
  770. Placeholder(_) => self.create_placeholder(mount, index, dom, to),
  771. Component(component) => {
  772. let parent = Some(ElementRef {
  773. path: ElementPath {
  774. path: self.template.get().node_paths[index],
  775. },
  776. mount,
  777. });
  778. self.create_component_node(mount, index, component, parent, dom, to)
  779. }
  780. Fragment(frag) => {
  781. let parent = Some(ElementRef {
  782. path: ElementPath {
  783. path: self.template.get().node_paths[index],
  784. },
  785. mount,
  786. });
  787. dom.create_children(to, frag, parent)
  788. }
  789. }
  790. }
  791. /// Mount a root node and return its ID and the path to the node
  792. fn mount_dynamic_node_with_path(
  793. &self,
  794. mount: MountId,
  795. idx: usize,
  796. dom: &mut VirtualDom,
  797. ) -> (ElementId, &'static [u8]) {
  798. // Add the mutation to the list
  799. let path = self.template.get().node_paths[idx];
  800. // Allocate a dynamic element reference for this text node
  801. let new_id = mount.mount_node(idx, dom);
  802. (new_id, &path[1..])
  803. }
  804. fn create_dynamic_text(
  805. &self,
  806. mount: MountId,
  807. idx: usize,
  808. text: &VText,
  809. dom: &mut VirtualDom,
  810. to: &mut impl WriteMutations,
  811. ) -> usize {
  812. let (new_id, path) = self.mount_dynamic_node_with_path(mount, idx, dom);
  813. // Hydrate the text node
  814. to.hydrate_text_node(path, &text.value, new_id);
  815. // Since we're hydrating an existing node, we don't create any new nodes
  816. 0
  817. }
  818. pub(crate) fn create_placeholder(
  819. &self,
  820. mount: MountId,
  821. idx: usize,
  822. dom: &mut VirtualDom,
  823. to: &mut impl WriteMutations,
  824. ) -> usize {
  825. let (id, path) = self.mount_dynamic_node_with_path(mount, idx, dom);
  826. // Assign the ID to the existing node in the template
  827. to.assign_node_id(path, id);
  828. // Since the placeholder is already in the DOM, we don't create any new nodes
  829. 0
  830. }
  831. }
  832. impl MountId {
  833. fn mount_node(self, node_index: usize, dom: &mut VirtualDom) -> ElementId {
  834. let id = dom.next_element();
  835. dom.mounts[self.0].mounted_dynamic_nodes[node_index] = id.0;
  836. id
  837. }
  838. }
  839. fn collect_dyn_node_range(
  840. dynamic_nodes: &mut Peekable<impl Iterator<Item = ((usize, usize), &'static [u8])>>,
  841. root_idx: u8,
  842. ) -> Option<(usize, usize)> {
  843. let start = match dynamic_nodes.peek() {
  844. Some(((_, idx), [first, ..])) if *first == root_idx => *idx,
  845. _ => return None,
  846. };
  847. let mut end = start;
  848. while let Some(((_, idx), p)) =
  849. dynamic_nodes.next_if(|(_, p)| matches!(p, [idx, ..] if *idx == root_idx))
  850. {
  851. if p.len() == 1 {
  852. continue;
  853. }
  854. end = idx;
  855. }
  856. Some((start, end))
  857. }
  858. fn matching_components<'a>(
  859. left: &'a VNode,
  860. right: &'a VNode,
  861. ) -> Option<Vec<(&'a VComponent, &'a VComponent)>> {
  862. let left_node = left.template.get();
  863. let right_node = right.template.get();
  864. if left_node.roots.len() != right_node.roots.len() {
  865. return None;
  866. }
  867. // run through the components, ensuring they're the same
  868. left_node
  869. .roots
  870. .iter()
  871. .zip(right_node.roots.iter())
  872. .map(|(l, r)| {
  873. let (l, r) = match (l, r) {
  874. (TemplateNode::Dynamic { id: l }, TemplateNode::Dynamic { id: r }) => (l, r),
  875. _ => return None,
  876. };
  877. let (l, r) = match (&left.dynamic_nodes[*l], &right.dynamic_nodes[*r]) {
  878. (Component(l), Component(r)) => (l, r),
  879. _ => return None,
  880. };
  881. Some((l, r))
  882. })
  883. .collect()
  884. }
  885. #[cfg(debug_assertions)]
  886. fn sort_bfs(paths: &[&'static [u8]]) -> Vec<(usize, &'static [u8])> {
  887. let mut with_indecies = paths.iter().copied().enumerate().collect::<Vec<_>>();
  888. with_indecies.sort_unstable_by(|(_, a), (_, b)| {
  889. let mut a = a.iter();
  890. let mut b = b.iter();
  891. loop {
  892. match (a.next(), b.next()) {
  893. (Some(a), Some(b)) => {
  894. if a != b {
  895. return a.cmp(b);
  896. }
  897. }
  898. // The shorter path goes first
  899. (None, Some(_)) => return std::cmp::Ordering::Less,
  900. (Some(_), None) => return std::cmp::Ordering::Greater,
  901. (None, None) => return std::cmp::Ordering::Equal,
  902. }
  903. }
  904. });
  905. with_indecies
  906. }
  907. #[test]
  908. #[cfg(debug_assertions)]
  909. fn sorting() {
  910. let r: [(usize, &[u8]); 5] = [
  911. (0, &[0, 1]),
  912. (1, &[0, 2]),
  913. (2, &[1, 0]),
  914. (3, &[1, 0, 1]),
  915. (4, &[1, 2]),
  916. ];
  917. assert_eq!(
  918. sort_bfs(&[&[0, 1,], &[0, 2,], &[1, 0,], &[1, 0, 1,], &[1, 2,],]),
  919. r
  920. );
  921. let r: [(usize, &[u8]); 6] = [
  922. (0, &[0]),
  923. (1, &[0, 1]),
  924. (2, &[0, 1, 2]),
  925. (3, &[1]),
  926. (4, &[1, 2]),
  927. (5, &[2]),
  928. ];
  929. assert_eq!(
  930. sort_bfs(&[&[0], &[0, 1], &[0, 1, 2], &[1], &[1, 2], &[2],]),
  931. r
  932. );
  933. }