node.rs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  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, VNodeMount, VText},
  8. nodes::DynamicNode,
  9. scopes::ScopeId,
  10. TemplateNode,
  11. };
  12. impl VNode {
  13. pub(crate) fn diff_node(
  14. &self,
  15. new: &VNode,
  16. dom: &mut VirtualDom,
  17. mut to: Option<&mut impl WriteMutations>,
  18. ) {
  19. // The node we are diffing from should always be mounted
  20. debug_assert!(
  21. dom.runtime
  22. .mounts
  23. .borrow()
  24. .get(self.mount.get().0)
  25. .is_some()
  26. || to.is_none()
  27. );
  28. // If the templates are different, we need to replace the entire template
  29. if self.template != new.template {
  30. let mount_id = self.mount.get();
  31. let parent = dom.get_mounted_parent(mount_id);
  32. return self.replace(std::slice::from_ref(new), parent, dom, to);
  33. }
  34. self.move_mount_to(new, dom);
  35. // If the templates are the same, we don't need to do anything, except copy over the mount information
  36. if self == new {
  37. return;
  38. }
  39. // If the templates are the same, we can diff the attributes and children
  40. // Start with the attributes
  41. // Since the attributes are only side effects, we can skip diffing them entirely if the node is suspended and we aren't outputting mutations
  42. if let Some(to) = to.as_deref_mut() {
  43. self.diff_attributes(new, dom, to);
  44. }
  45. // Now diff the dynamic nodes
  46. let mount_id = new.mount.get();
  47. for (dyn_node_idx, (old, new)) in self
  48. .dynamic_nodes
  49. .iter()
  50. .zip(new.dynamic_nodes.iter())
  51. .enumerate()
  52. {
  53. self.diff_dynamic_node(mount_id, dyn_node_idx, old, new, dom, to.as_deref_mut())
  54. }
  55. }
  56. fn move_mount_to(&self, new: &VNode, dom: &mut VirtualDom) {
  57. // Copy over the mount information
  58. let mount_id = self.mount.take();
  59. new.mount.set(mount_id);
  60. if mount_id.mounted() {
  61. let mut mounts = dom.runtime.mounts.borrow_mut();
  62. let mount = &mut mounts[mount_id.0];
  63. // Update the reference to the node for bubbling events
  64. mount.node = new.clone();
  65. }
  66. }
  67. fn diff_dynamic_node(
  68. &self,
  69. mount: MountId,
  70. idx: usize,
  71. old_node: &DynamicNode,
  72. new_node: &DynamicNode,
  73. dom: &mut VirtualDom,
  74. mut to: Option<&mut impl WriteMutations>,
  75. ) {
  76. tracing::trace!("diffing dynamic node from {old_node:?} to {new_node:?}");
  77. match (old_node, new_node) {
  78. (Text(old), Text(new)) => {
  79. // Diffing text is just a side effect, if we are diffing suspended nodes and are not outputting mutations, we can skip it
  80. if let Some(to) = to {
  81. let id = ElementId(dom.get_mounted_dyn_node(mount, idx));
  82. self.diff_vtext(to, id, old, new)
  83. }
  84. }
  85. (Placeholder(_), Placeholder(_)) => {}
  86. (Fragment(old), Fragment(new)) => dom.diff_non_empty_fragment(
  87. to,
  88. old,
  89. new,
  90. Some(self.reference_to_dynamic_node(mount, idx)),
  91. ),
  92. (Component(old), Component(new)) => {
  93. let scope_id = ScopeId(dom.get_mounted_dyn_node(mount, idx));
  94. self.diff_vcomponent(
  95. mount,
  96. idx,
  97. new,
  98. old,
  99. scope_id,
  100. Some(self.reference_to_dynamic_node(mount, idx)),
  101. dom,
  102. to,
  103. )
  104. }
  105. (old, new) => {
  106. // TODO: we should pass around the mount instead of the mount id
  107. // that would make moving the mount around here much easier
  108. // Mark the mount as unused. When a scope is created, it reads the mount and
  109. // if it is the placeholder value, it will create the scope, otherwise it will
  110. // reuse the scope
  111. let old_mount = dom.get_mounted_dyn_node(mount, idx);
  112. dom.set_mounted_dyn_node(mount, idx, usize::MAX);
  113. let new_nodes_on_stack =
  114. self.create_dynamic_node(new, mount, idx, dom, to.as_deref_mut());
  115. // Restore the mount for the scope we are removing
  116. let new_mount = dom.get_mounted_dyn_node(mount, idx);
  117. dom.set_mounted_dyn_node(mount, idx, old_mount);
  118. self.remove_dynamic_node(mount, dom, to, true, idx, old, Some(new_nodes_on_stack));
  119. // Restore the mount for the node we created
  120. dom.set_mounted_dyn_node(mount, idx, new_mount);
  121. }
  122. };
  123. }
  124. /// Try to get the dynamic node and its index for a root node
  125. pub(crate) fn get_dynamic_root_node_and_id(
  126. &self,
  127. root_idx: usize,
  128. ) -> Option<(usize, &DynamicNode)> {
  129. self.template.roots[root_idx]
  130. .dynamic_id()
  131. .map(|id| (id, &self.dynamic_nodes[id]))
  132. }
  133. pub(crate) fn find_first_element(&self, dom: &VirtualDom) -> ElementId {
  134. let mount_id = self.mount.get();
  135. let first = match self.get_dynamic_root_node_and_id(0) {
  136. // This node is static, just get the root id
  137. None => dom.get_mounted_root_node(mount_id, 0),
  138. // If it is dynamic and shallow, grab the id from the mounted dynamic nodes
  139. Some((idx, Placeholder(_) | Text(_))) => {
  140. ElementId(dom.get_mounted_dyn_node(mount_id, idx))
  141. }
  142. // The node is a fragment, so we need to find the first element in the fragment
  143. Some((_, Fragment(children))) => {
  144. let child = children.first().unwrap();
  145. child.find_first_element(dom)
  146. }
  147. // The node is a component, so we need to find the first element in the component
  148. Some((id, Component(_))) => {
  149. let scope = ScopeId(dom.get_mounted_dyn_node(mount_id, id));
  150. dom.get_scope(scope)
  151. .unwrap()
  152. .root_node()
  153. .find_first_element(dom)
  154. }
  155. };
  156. // The first element should never be the default element id (the root element)
  157. debug_assert_ne!(first, ElementId::default());
  158. first
  159. }
  160. pub(crate) fn find_last_element(&self, dom: &VirtualDom) -> ElementId {
  161. let mount_id = self.mount.get();
  162. let last_root_index = self.template.roots.len() - 1;
  163. let last = match self.get_dynamic_root_node_and_id(last_root_index) {
  164. // This node is static, just get the root id
  165. None => dom.get_mounted_root_node(mount_id, last_root_index),
  166. // If it is dynamic and shallow, grab the id from the mounted dynamic nodes
  167. Some((idx, Placeholder(_) | Text(_))) => {
  168. ElementId(dom.get_mounted_dyn_node(mount_id, idx))
  169. }
  170. // The node is a fragment, so we need to find the first element in the fragment
  171. Some((_, Fragment(children))) => {
  172. let child = children.first().unwrap();
  173. child.find_first_element(dom)
  174. }
  175. // The node is a component, so we need to find the first element in the component
  176. Some((id, Component(_))) => {
  177. let scope = ScopeId(dom.get_mounted_dyn_node(mount_id, id));
  178. dom.get_scope(scope)
  179. .unwrap()
  180. .root_node()
  181. .find_last_element(dom)
  182. }
  183. };
  184. // The last element should never be the default element id (the root element)
  185. debug_assert_ne!(last, ElementId::default());
  186. last
  187. }
  188. /// Diff the two text nodes
  189. ///
  190. /// This just sets the text of the node if it's different.
  191. fn diff_vtext(&self, to: &mut impl WriteMutations, id: ElementId, left: &VText, right: &VText) {
  192. if left.value != right.value {
  193. to.set_node_text(&right.value, id);
  194. }
  195. }
  196. pub(crate) fn replace(
  197. &self,
  198. right: &[VNode],
  199. parent: Option<ElementRef>,
  200. dom: &mut VirtualDom,
  201. to: Option<&mut impl WriteMutations>,
  202. ) {
  203. self.replace_inner(right, parent, dom, to, true)
  204. }
  205. /// Replace this node with new children, but *don't destroy* the old node's component state
  206. ///
  207. /// This is useful for moving a node from the rendered nodes into a suspended node
  208. pub(crate) fn move_node_to_background(
  209. &self,
  210. right: &[VNode],
  211. parent: Option<ElementRef>,
  212. dom: &mut VirtualDom,
  213. to: Option<&mut impl WriteMutations>,
  214. ) {
  215. self.replace_inner(right, parent, dom, to, false)
  216. }
  217. pub(crate) fn replace_inner(
  218. &self,
  219. right: &[VNode],
  220. parent: Option<ElementRef>,
  221. dom: &mut VirtualDom,
  222. mut to: Option<&mut impl WriteMutations>,
  223. destroy_component_state: bool,
  224. ) {
  225. let m = dom.create_children(to.as_deref_mut(), right, parent);
  226. // Instead of *just* removing it, we can use the replace mutation
  227. self.remove_node_inner(dom, to, destroy_component_state, Some(m))
  228. }
  229. /// Remove a node from the dom and potentially replace it with the top m nodes from the stack
  230. pub(crate) fn remove_node<M: WriteMutations>(
  231. &self,
  232. dom: &mut VirtualDom,
  233. to: Option<&mut M>,
  234. replace_with: Option<usize>,
  235. ) {
  236. self.remove_node_inner(dom, to, true, replace_with)
  237. }
  238. /// Remove a node, but only maybe destroy the component state of that node. During suspense, we need to remove a node from the real dom without wiping the component state
  239. pub(crate) fn remove_node_inner<M: WriteMutations>(
  240. &self,
  241. dom: &mut VirtualDom,
  242. to: Option<&mut M>,
  243. destroy_component_state: bool,
  244. replace_with: Option<usize>,
  245. ) {
  246. let mount = self.mount.get();
  247. if !mount.mounted() {
  248. return;
  249. }
  250. // Clean up any attributes that have claimed a static node as dynamic for mount/unmounts
  251. // Will not generate mutations!
  252. self.reclaim_attributes(mount, dom);
  253. // Remove the nested dynamic nodes
  254. // We don't generate mutations for these, as they will be removed by the parent (in the next line)
  255. // But we still need to make sure to reclaim them from the arena and drop their hooks, etc
  256. self.remove_nested_dyn_nodes::<M>(mount, dom, destroy_component_state);
  257. // Clean up the roots, assuming we need to generate mutations for these
  258. // This is done last in order to preserve Node ID reclaim order (reclaim in reverse order of claim)
  259. self.reclaim_roots(mount, dom, to, destroy_component_state, replace_with);
  260. if destroy_component_state {
  261. let mount = self.mount.take();
  262. // Remove the mount information
  263. dom.runtime.mounts.borrow_mut().remove(mount.0);
  264. }
  265. }
  266. fn reclaim_roots(
  267. &self,
  268. mount: MountId,
  269. dom: &mut VirtualDom,
  270. mut to: Option<&mut impl WriteMutations>,
  271. destroy_component_state: bool,
  272. replace_with: Option<usize>,
  273. ) {
  274. let roots = self.template.roots;
  275. for (idx, node) in roots.iter().enumerate() {
  276. let last_node = idx == roots.len() - 1;
  277. if let Some(id) = node.dynamic_id() {
  278. let dynamic_node = &self.dynamic_nodes[id];
  279. self.remove_dynamic_node(
  280. mount,
  281. dom,
  282. to.as_deref_mut(),
  283. destroy_component_state,
  284. id,
  285. dynamic_node,
  286. replace_with.filter(|_| last_node),
  287. );
  288. } else if let Some(to) = to.as_deref_mut() {
  289. let id = dom.get_mounted_root_node(mount, idx);
  290. if let (true, Some(replace_with)) = (last_node, replace_with) {
  291. to.replace_node_with(id, replace_with);
  292. } else {
  293. to.remove_node(id);
  294. }
  295. dom.reclaim(id);
  296. }
  297. }
  298. }
  299. fn remove_nested_dyn_nodes<M: WriteMutations>(
  300. &self,
  301. mount: MountId,
  302. dom: &mut VirtualDom,
  303. destroy_component_state: bool,
  304. ) {
  305. let template = self.template;
  306. for (idx, dyn_node) in self.dynamic_nodes.iter().enumerate() {
  307. let path_len = template.node_paths.get(idx).map(|path| path.len());
  308. // Roots are cleaned up automatically above and nodes with a empty path are placeholders
  309. if let Some(2..) = path_len {
  310. self.remove_dynamic_node(
  311. mount,
  312. dom,
  313. Option::<&mut M>::None,
  314. destroy_component_state,
  315. idx,
  316. dyn_node,
  317. None,
  318. )
  319. }
  320. }
  321. }
  322. fn remove_dynamic_node(
  323. &self,
  324. mount: MountId,
  325. dom: &mut VirtualDom,
  326. mut to: Option<&mut impl WriteMutations>,
  327. destroy_component_state: bool,
  328. idx: usize,
  329. node: &DynamicNode,
  330. replace_with: Option<usize>,
  331. ) {
  332. match node {
  333. Component(_comp) => {
  334. let scope_id = ScopeId(dom.get_mounted_dyn_node(mount, idx));
  335. dom.remove_component_node(to, destroy_component_state, scope_id, replace_with);
  336. }
  337. Text(_) | Placeholder(_) => {
  338. let id = ElementId(dom.get_mounted_dyn_node(mount, idx));
  339. if let Some(to) = to {
  340. if let Some(replace_with) = replace_with {
  341. to.replace_node_with(id, replace_with);
  342. } else {
  343. to.remove_node(id);
  344. }
  345. dom.reclaim(id)
  346. }
  347. }
  348. Fragment(nodes) => {
  349. for node in &nodes[..nodes.len() - 1] {
  350. node.remove_node_inner(dom, to.as_deref_mut(), destroy_component_state, None)
  351. }
  352. if let Some(last_node) = nodes.last() {
  353. last_node.remove_node_inner(dom, to, destroy_component_state, replace_with)
  354. }
  355. }
  356. };
  357. }
  358. pub(super) fn reclaim_attributes(&self, mount: MountId, dom: &mut VirtualDom) {
  359. let mut next_id = None;
  360. for (idx, path) in self.template.attr_paths.iter().enumerate() {
  361. // We clean up the roots in the next step, so don't worry about them here
  362. if path.len() <= 1 {
  363. continue;
  364. }
  365. // only reclaim the new element if it's different from the previous one
  366. let new_id = dom.get_mounted_dyn_attr(mount, idx);
  367. if Some(new_id) != next_id {
  368. dom.reclaim(new_id);
  369. next_id = Some(new_id);
  370. }
  371. }
  372. }
  373. pub(super) fn diff_attributes(
  374. &self,
  375. new: &VNode,
  376. dom: &mut VirtualDom,
  377. to: &mut impl WriteMutations,
  378. ) {
  379. let mount_id = new.mount.get();
  380. for (idx, (old_attrs, new_attrs)) in self
  381. .dynamic_attrs
  382. .iter()
  383. .zip(new.dynamic_attrs.iter())
  384. .enumerate()
  385. {
  386. let mut old_attributes_iter = old_attrs.iter().peekable();
  387. let mut new_attributes_iter = new_attrs.iter().peekable();
  388. let attribute_id = dom.get_mounted_dyn_attr(mount_id, idx);
  389. let path = self.template.attr_paths[idx];
  390. loop {
  391. match (old_attributes_iter.peek(), new_attributes_iter.peek()) {
  392. (Some(old_attribute), Some(new_attribute)) => {
  393. // check which name is greater
  394. match old_attribute.name.cmp(new_attribute.name) {
  395. // The two attributes are the same, so diff them
  396. std::cmp::Ordering::Equal => {
  397. let old = old_attributes_iter.next().unwrap();
  398. let new = new_attributes_iter.next().unwrap();
  399. // Volatile attributes are attributes that the browser may override so we always update them
  400. let volatile = old.volatile;
  401. if volatile || old.value != new.value {
  402. self.write_attribute(
  403. path,
  404. new,
  405. attribute_id,
  406. mount_id,
  407. dom,
  408. to,
  409. );
  410. }
  411. }
  412. // In a sorted list, if the old attribute name is first, then the new attribute is missing
  413. std::cmp::Ordering::Less => {
  414. let old = old_attributes_iter.next().unwrap();
  415. self.remove_attribute(old, attribute_id, to)
  416. }
  417. // In a sorted list, if the new attribute name is first, then the old attribute is missing
  418. std::cmp::Ordering::Greater => {
  419. let new = new_attributes_iter.next().unwrap();
  420. self.write_attribute(path, new, attribute_id, mount_id, dom, to);
  421. }
  422. }
  423. }
  424. (Some(_), None) => {
  425. let left = old_attributes_iter.next().unwrap();
  426. self.remove_attribute(left, attribute_id, to)
  427. }
  428. (None, Some(_)) => {
  429. let right = new_attributes_iter.next().unwrap();
  430. self.write_attribute(path, right, attribute_id, mount_id, dom, to)
  431. }
  432. (None, None) => break,
  433. }
  434. }
  435. }
  436. }
  437. fn remove_attribute(&self, attribute: &Attribute, id: ElementId, to: &mut impl WriteMutations) {
  438. match &attribute.value {
  439. AttributeValue::Listener(_) => {
  440. to.remove_event_listener(&attribute.name[2..], id);
  441. }
  442. _ => {
  443. to.set_attribute(
  444. attribute.name,
  445. attribute.namespace,
  446. &AttributeValue::None,
  447. id,
  448. );
  449. }
  450. }
  451. }
  452. fn write_attribute(
  453. &self,
  454. path: &'static [u8],
  455. attribute: &Attribute,
  456. id: ElementId,
  457. mount: MountId,
  458. dom: &mut VirtualDom,
  459. to: &mut impl WriteMutations,
  460. ) {
  461. match &attribute.value {
  462. AttributeValue::Listener(_) => {
  463. let element_ref = ElementRef {
  464. path: ElementPath { path },
  465. mount,
  466. };
  467. let mut elements = dom.runtime.elements.borrow_mut();
  468. elements[id.0] = Some(element_ref);
  469. to.create_event_listener(&attribute.name[2..], id);
  470. }
  471. _ => {
  472. to.set_attribute(attribute.name, attribute.namespace, &attribute.value, id);
  473. }
  474. }
  475. }
  476. /// Create this rsx block. This will create scopes from components that this rsx block contains, but it will not write anything to the DOM.
  477. pub(crate) fn create(
  478. &self,
  479. dom: &mut VirtualDom,
  480. parent: Option<ElementRef>,
  481. mut to: Option<&mut impl WriteMutations>,
  482. ) -> usize {
  483. // Get the most up to date template
  484. let template = self.template;
  485. // Initialize the mount information for this vnode if it isn't already mounted
  486. if !self.mount.get().mounted() {
  487. let mut mounts = dom.runtime.mounts.borrow_mut();
  488. let entry = mounts.vacant_entry();
  489. let mount = MountId(entry.key());
  490. self.mount.set(mount);
  491. tracing::trace!(?self, ?mount, "creating template");
  492. entry.insert(VNodeMount {
  493. node: self.clone(),
  494. parent,
  495. root_ids: vec![ElementId(0); template.roots.len()].into_boxed_slice(),
  496. mounted_attributes: vec![ElementId(0); template.attr_paths.len()]
  497. .into_boxed_slice(),
  498. mounted_dynamic_nodes: vec![usize::MAX; template.node_paths.len()]
  499. .into_boxed_slice(),
  500. });
  501. }
  502. // Walk the roots, creating nodes and assigning IDs
  503. // nodes in an iterator of (dynamic_node_index, path) and attrs in an iterator of (attr_index, path)
  504. let mut nodes = template.node_paths.iter().copied().enumerate().peekable();
  505. let mut attrs = template.attr_paths.iter().copied().enumerate().peekable();
  506. // Get the mounted id of this block
  507. // At this point, we should have already mounted the block
  508. debug_assert!(
  509. dom.runtime.mounts.borrow().contains(
  510. self.mount
  511. .get()
  512. .as_usize()
  513. .expect("node should already be mounted"),
  514. ),
  515. "Tried to find mount {:?} in dom.mounts, but it wasn't there",
  516. self.mount.get()
  517. );
  518. let mount = self.mount.get();
  519. // Go through each root node and create the node, adding it to the stack.
  520. // Each node already exists in the template, so we can just clone it from the template
  521. let nodes_created = template
  522. .roots
  523. .iter()
  524. .enumerate()
  525. .map(|(root_idx, root)| {
  526. match root {
  527. TemplateNode::Dynamic { id } => {
  528. // Take a dynamic node off the depth first iterator
  529. nodes.next().unwrap();
  530. // Then mount the node
  531. self.create_dynamic_node(
  532. &self.dynamic_nodes[*id],
  533. mount,
  534. *id,
  535. dom,
  536. to.as_deref_mut(),
  537. )
  538. }
  539. // For static text and element nodes, just load the template root. This may be a placeholder or just a static node. We now know that each root node has a unique id
  540. TemplateNode::Text { .. } | TemplateNode::Element { .. } => {
  541. if let Some(to) = to.as_deref_mut() {
  542. self.load_template_root(mount, root_idx, dom, to);
  543. }
  544. // If this is an element, load in all of the placeholder or dynamic content under this root element too
  545. if matches!(root, TemplateNode::Element { .. }) {
  546. // This operation relies on the fact that the root node is the top node on the stack so we need to do it here
  547. self.load_placeholders(
  548. mount,
  549. &mut nodes,
  550. root_idx as u8,
  551. dom,
  552. to.as_deref_mut(),
  553. );
  554. // Now write out any attributes we need
  555. if let Some(to) = to.as_deref_mut() {
  556. self.write_attrs(mount, &mut attrs, root_idx as u8, dom, to);
  557. }
  558. }
  559. // This creates one node on the stack
  560. 1
  561. }
  562. }
  563. })
  564. .sum();
  565. // And return the number of nodes we created on the stack
  566. nodes_created
  567. }
  568. }
  569. impl VNode {
  570. /// Get a reference back into a dynamic node
  571. fn reference_to_dynamic_node(&self, mount: MountId, dynamic_node_id: usize) -> ElementRef {
  572. ElementRef {
  573. path: ElementPath {
  574. path: self.template.node_paths[dynamic_node_id],
  575. },
  576. mount,
  577. }
  578. }
  579. pub(crate) fn create_dynamic_node(
  580. &self,
  581. node: &DynamicNode,
  582. mount: MountId,
  583. dynamic_node_id: usize,
  584. dom: &mut VirtualDom,
  585. to: Option<&mut impl WriteMutations>,
  586. ) -> usize {
  587. use DynamicNode::*;
  588. match node {
  589. Component(component) => {
  590. let parent = Some(self.reference_to_dynamic_node(mount, dynamic_node_id));
  591. self.create_component_node(mount, dynamic_node_id, component, parent, dom, to)
  592. }
  593. Fragment(frag) => {
  594. let parent = Some(self.reference_to_dynamic_node(mount, dynamic_node_id));
  595. dom.create_children(to, frag, parent)
  596. }
  597. Text(text) => {
  598. // If we are diffing suspended nodes and are not outputting mutations, we can skip it
  599. if let Some(to) = to {
  600. self.create_dynamic_text(mount, dynamic_node_id, text, dom, to)
  601. } else {
  602. 0
  603. }
  604. }
  605. Placeholder(_) => {
  606. // If we are diffing suspended nodes and are not outputting mutations, we can skip it
  607. if let Some(to) = to {
  608. tracing::trace!("creating placeholder");
  609. self.create_placeholder(mount, dynamic_node_id, dom, to)
  610. } else {
  611. tracing::trace!("skipping creating placeholder");
  612. 0
  613. }
  614. }
  615. }
  616. }
  617. /// Load all of the placeholder nodes for descendent of this root node
  618. ///
  619. /// ```rust, no_run
  620. /// # use dioxus::prelude::*;
  621. /// # let some_text = "hello world";
  622. /// # let some_value = "123";
  623. /// rsx! {
  624. /// div { // We just wrote this node
  625. /// // This is a placeholder
  626. /// {some_value}
  627. ///
  628. /// // Load this too
  629. /// "{some_text}"
  630. /// }
  631. /// };
  632. /// ```
  633. ///
  634. /// IMPORTANT: This function assumes that root node is the top node on the stack
  635. fn load_placeholders(
  636. &self,
  637. mount: MountId,
  638. dynamic_nodes_iter: &mut Peekable<impl Iterator<Item = (usize, &'static [u8])>>,
  639. root_idx: u8,
  640. dom: &mut VirtualDom,
  641. mut to: Option<&mut impl WriteMutations>,
  642. ) {
  643. // Only take nodes that are under this root node
  644. let from_root_node = |(_, path): &(usize, &[u8])| path.first() == Some(&root_idx);
  645. while let Some((dynamic_node_id, path)) = dynamic_nodes_iter.next_if(from_root_node) {
  646. let m = self.create_dynamic_node(
  647. &self.dynamic_nodes[dynamic_node_id],
  648. mount,
  649. dynamic_node_id,
  650. dom,
  651. to.as_deref_mut(),
  652. );
  653. if let Some(to) = to.as_deref_mut() {
  654. // If we actually created real new nodes, we need to replace the placeholder for this dynamic node with the new dynamic nodes
  655. if m > 0 {
  656. // The path is one shorter because the top node is the root
  657. let path = &path[1..];
  658. to.replace_placeholder_with_nodes(path, m);
  659. }
  660. }
  661. }
  662. }
  663. /// After we have written a root element, we need to write all the attributes that are on the root node
  664. ///
  665. /// ```rust, ignore
  666. /// rsx! {
  667. /// div { // We just wrote this node
  668. /// class: "{class}", // We need to set these attributes
  669. /// id: "{id}",
  670. /// style: "{style}",
  671. /// }
  672. /// }
  673. /// ```
  674. ///
  675. /// IMPORTANT: This function assumes that root node is the top node on the stack
  676. fn write_attrs(
  677. &self,
  678. mount: MountId,
  679. dynamic_attrbiutes_iter: &mut Peekable<impl Iterator<Item = (usize, &'static [u8])>>,
  680. root_idx: u8,
  681. dom: &mut VirtualDom,
  682. to: &mut impl WriteMutations,
  683. ) {
  684. let mut last_path = None;
  685. // Only take nodes that are under this root node
  686. let from_root_node = |(_, path): &(usize, &[u8])| path.first() == Some(&root_idx);
  687. while let Some((attribute_idx, attribute_path)) =
  688. dynamic_attrbiutes_iter.next_if(from_root_node)
  689. {
  690. let attribute = &self.dynamic_attrs[attribute_idx];
  691. let id = match last_path {
  692. // If the last path was exactly the same, we can reuse the id
  693. Some((path, id)) if path == attribute_path => id,
  694. // Otherwise, we need to create a new id
  695. _ => {
  696. let id = self.assign_static_node_as_dynamic(mount, attribute_path, dom, to);
  697. last_path = Some((attribute_path, id));
  698. id
  699. }
  700. };
  701. for attr in &**attribute {
  702. self.write_attribute(attribute_path, attr, id, mount, dom, to);
  703. dom.set_mounted_dyn_attr(mount, attribute_idx, id);
  704. }
  705. }
  706. }
  707. fn load_template_root(
  708. &self,
  709. mount: MountId,
  710. root_idx: usize,
  711. dom: &mut VirtualDom,
  712. to: &mut impl WriteMutations,
  713. ) -> ElementId {
  714. // Get an ID for this root since it's a real root
  715. let this_id = dom.next_element();
  716. dom.set_mounted_root_node(mount, root_idx, this_id);
  717. to.load_template(self.template, root_idx, this_id);
  718. this_id
  719. }
  720. /// We have some dynamic attributes attached to a some node
  721. ///
  722. /// That node needs to be loaded at runtime, so we need to give it an ID
  723. ///
  724. /// If the node in question is the root node, we just return the ID
  725. ///
  726. /// If the node is not on the stack, we create a new ID for it and assign it
  727. fn assign_static_node_as_dynamic(
  728. &self,
  729. mount: MountId,
  730. path: &'static [u8],
  731. dom: &mut VirtualDom,
  732. to: &mut impl WriteMutations,
  733. ) -> ElementId {
  734. // This is just the root node. We already know it's id
  735. if let [root_idx] = path {
  736. return dom.get_mounted_root_node(mount, *root_idx as usize);
  737. }
  738. // The node is deeper in the template and we should create a new id for it
  739. let id = dom.next_element();
  740. to.assign_node_id(&path[1..], id);
  741. id
  742. }
  743. fn create_dynamic_text(
  744. &self,
  745. mount: MountId,
  746. idx: usize,
  747. text: &VText,
  748. dom: &mut VirtualDom,
  749. to: &mut impl WriteMutations,
  750. ) -> usize {
  751. let new_id = mount.mount_node(idx, dom);
  752. // If this is a root node, the path is empty and we need to create a new text node
  753. to.create_text_node(&text.value, new_id);
  754. // We create one node on the stack
  755. 1
  756. }
  757. pub(crate) fn create_placeholder(
  758. &self,
  759. mount: MountId,
  760. idx: usize,
  761. dom: &mut VirtualDom,
  762. to: &mut impl WriteMutations,
  763. ) -> usize {
  764. let new_id = mount.mount_node(idx, dom);
  765. // If this is a root node, the path is empty and we need to create a new placeholder node
  766. to.create_placeholder(new_id);
  767. // We create one node on the stack
  768. 1
  769. }
  770. }
  771. impl MountId {
  772. fn mount_node(self, node_index: usize, dom: &mut VirtualDom) -> ElementId {
  773. let id = dom.next_element();
  774. dom.set_mounted_dyn_node(self, node_index, id.0);
  775. id
  776. }
  777. }