create.rs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. use crate::any_props::AnyProps;
  2. use crate::innerlude::{BorrowedAttributeValue, VComponent, VPlaceholder, VText};
  3. use crate::mutations::Mutation;
  4. use crate::mutations::Mutation::*;
  5. use crate::nodes::VNode;
  6. use crate::nodes::{DynamicNode, TemplateNode};
  7. use crate::virtual_dom::VirtualDom;
  8. use crate::{AttributeValue, ElementId, RenderReturn, ScopeId, SuspenseContext, Template};
  9. use std::cell::Cell;
  10. use std::iter::Peekable;
  11. use std::rc::Rc;
  12. use TemplateNode::*;
  13. #[cfg(debug_assertions)]
  14. fn sort_bfs(paths: &[&'static [u8]]) -> Vec<(usize, &'static [u8])> {
  15. let mut with_indecies = paths.iter().copied().enumerate().collect::<Vec<_>>();
  16. with_indecies.sort_unstable_by(|(_, a), (_, b)| {
  17. let mut a = a.iter();
  18. let mut b = b.iter();
  19. loop {
  20. match (a.next(), b.next()) {
  21. (Some(a), Some(b)) => {
  22. if a != b {
  23. return a.cmp(b);
  24. }
  25. }
  26. // The shorter path goes first
  27. (None, Some(_)) => return std::cmp::Ordering::Less,
  28. (Some(_), None) => return std::cmp::Ordering::Greater,
  29. (None, None) => return std::cmp::Ordering::Equal,
  30. }
  31. }
  32. });
  33. with_indecies
  34. }
  35. #[test]
  36. #[cfg(debug_assertions)]
  37. fn sorting() {
  38. let r: [(usize, &[u8]); 5] = [
  39. (0, &[0, 1]),
  40. (1, &[0, 2]),
  41. (2, &[1, 0]),
  42. (3, &[1, 0, 1]),
  43. (4, &[1, 2]),
  44. ];
  45. assert_eq!(
  46. sort_bfs(&[&[0, 1,], &[0, 2,], &[1, 0,], &[1, 0, 1,], &[1, 2,],]),
  47. r
  48. );
  49. let r: [(usize, &[u8]); 6] = [
  50. (0, &[0]),
  51. (1, &[0, 1]),
  52. (2, &[0, 1, 2]),
  53. (3, &[1]),
  54. (4, &[1, 2]),
  55. (5, &[2]),
  56. ];
  57. assert_eq!(
  58. sort_bfs(&[&[0], &[0, 1], &[0, 1, 2], &[1], &[1, 2], &[2],]),
  59. r
  60. );
  61. }
  62. impl<'b> VirtualDom {
  63. /// Create a new template [`VNode`] and write it to the [`Mutations`] buffer.
  64. ///
  65. /// This method pushes the ScopeID to the internal scopestack and returns the number of nodes created.
  66. pub(crate) fn create_scope(&mut self, scope: ScopeId, template: &'b VNode<'b>) -> usize {
  67. self.scope_stack.push(scope);
  68. let out = self.create(template);
  69. self.scope_stack.pop();
  70. out
  71. }
  72. /// Create this template and write its mutations
  73. pub(crate) fn create(&mut self, node: &'b VNode<'b>) -> usize {
  74. // check for a overriden template
  75. #[cfg(debug_assertions)]
  76. {
  77. let (path, byte_index) = node.template.get().name.rsplit_once(':').unwrap();
  78. if let Some(template) = self
  79. .templates
  80. .get(path)
  81. .and_then(|map| map.get(&byte_index.parse().unwrap()))
  82. {
  83. node.template.set(*template);
  84. }
  85. }
  86. // Intialize the root nodes slice
  87. node.root_ids
  88. .intialize(vec![ElementId(0); node.template.get().roots.len()].into_boxed_slice());
  89. // The best renderers will have templates prehydrated and registered
  90. // Just in case, let's create the template using instructions anyways
  91. self.register_template(node.template.get());
  92. // we know that this will generate at least one mutation per node
  93. self.mutations
  94. .edits
  95. .reserve(node.template.get().roots.len());
  96. // Walk the roots, creating nodes and assigning IDs
  97. // nodes in an iterator of ((dynamic_node_index, sorted_index), path)
  98. // todo: adjust dynamic nodes to be in the order of roots and then leaves (ie BFS)
  99. #[cfg(not(debug_assertions))]
  100. let (mut attrs, mut nodes) = (
  101. node.template
  102. .get()
  103. .attr_paths
  104. .iter()
  105. .copied()
  106. .enumerate()
  107. .peekable(),
  108. node.template
  109. .get()
  110. .node_paths
  111. .iter()
  112. .copied()
  113. .enumerate()
  114. .map(|(i, path)| ((i, i), path))
  115. .peekable(),
  116. );
  117. // 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
  118. #[cfg(debug_assertions)]
  119. let (attrs_sorted, nodes_sorted) = {
  120. (
  121. sort_bfs(node.template.get().attr_paths),
  122. sort_bfs(node.template.get().node_paths),
  123. )
  124. };
  125. #[cfg(debug_assertions)]
  126. let (mut attrs, mut nodes) = {
  127. (
  128. attrs_sorted.into_iter().peekable(),
  129. nodes_sorted
  130. .iter()
  131. .copied()
  132. .enumerate()
  133. .map(|(i, (id, path))| ((id, i), path))
  134. .peekable(),
  135. )
  136. };
  137. node.template
  138. .get()
  139. .roots
  140. .iter()
  141. .enumerate()
  142. .map(|(idx, root)| match root {
  143. DynamicText { id } | Dynamic { id } => {
  144. nodes.next().unwrap();
  145. self.write_dynamic_root(node, *id)
  146. }
  147. Element { .. } => {
  148. #[cfg(not(debug_assertions))]
  149. let id = self.write_element_root(node, idx, &mut attrs, &mut nodes, &[]);
  150. #[cfg(debug_assertions)]
  151. let id =
  152. self.write_element_root(node, idx, &mut attrs, &mut nodes, &nodes_sorted);
  153. id
  154. }
  155. Text { .. } => self.write_static_text_root(node, idx),
  156. })
  157. .sum()
  158. }
  159. fn write_static_text_root(&mut self, node: &VNode, idx: usize) -> usize {
  160. // Simply just load the template root, no modifications needed
  161. self.load_template_root(node, idx);
  162. // Text producs just one node on the stack
  163. 1
  164. }
  165. fn write_dynamic_root(&mut self, template: &'b VNode<'b>, idx: usize) -> usize {
  166. use DynamicNode::*;
  167. match &template.dynamic_nodes[idx] {
  168. node @ Component { .. } | node @ Fragment(_) => {
  169. self.create_dynamic_node(template, node, idx)
  170. }
  171. Placeholder(VPlaceholder { id }) => {
  172. let id = self.set_slot(template, id, idx);
  173. self.mutations.push(CreatePlaceholder { id });
  174. 1
  175. }
  176. Text(VText { id, value }) => {
  177. let id = self.set_slot(template, id, idx);
  178. self.create_static_text(value, id);
  179. 1
  180. }
  181. }
  182. }
  183. fn create_static_text(&mut self, value: &str, id: ElementId) {
  184. // Safety: we promise not to re-alias this text later on after committing it to the mutation
  185. let unbounded_text: &str = unsafe { std::mem::transmute(value) };
  186. self.mutations.push(CreateTextNode {
  187. value: unbounded_text,
  188. id,
  189. });
  190. }
  191. /// We write all the descndent data for this element
  192. ///
  193. /// Elements can contain other nodes - and those nodes can be dynamic or static
  194. ///
  195. /// We want to make sure we write these nodes while on top of the root
  196. fn write_element_root(
  197. &mut self,
  198. template: &'b VNode<'b>,
  199. root_idx: usize,
  200. dynamic_attrs: &mut Peekable<impl Iterator<Item = (usize, &'static [u8])>>,
  201. dynamic_nodes_iter: &mut Peekable<impl Iterator<Item = ((usize, usize), &'static [u8])>>,
  202. dynamic_nodes: &[(usize, &'static [u8])],
  203. ) -> usize {
  204. // Load the template root and get the ID for the node on the stack
  205. let root_on_stack = self.load_template_root(template, root_idx);
  206. // Write all the attributes below this root
  207. self.write_attrs_on_root(dynamic_attrs, root_idx as u8, root_on_stack, template);
  208. // Load in all of the placeholder or dynamic content under this root too
  209. self.load_placeholders(dynamic_nodes_iter, dynamic_nodes, root_idx as u8, template);
  210. 1
  211. }
  212. /// Load all of the placeholder nodes for descendents of this root node
  213. ///
  214. /// ```rust, ignore
  215. /// rsx! {
  216. /// div {
  217. /// // This is a placeholder
  218. /// some_value,
  219. ///
  220. /// // Load this too
  221. /// "{some_text}"
  222. /// }
  223. /// }
  224. /// ```
  225. #[allow(unused)]
  226. fn load_placeholders(
  227. &mut self,
  228. dynamic_nodes_iter: &mut Peekable<impl Iterator<Item = ((usize, usize), &'static [u8])>>,
  229. dynamic_nodes: &[(usize, &'static [u8])],
  230. root_idx: u8,
  231. template: &'b VNode<'b>,
  232. ) {
  233. let (start, end) = match collect_dyn_node_range(dynamic_nodes_iter, root_idx) {
  234. Some((a, b)) => (a, b),
  235. None => return,
  236. };
  237. // 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
  238. #[cfg(not(debug_assertions))]
  239. let reversed_iter = (start..=end).rev();
  240. #[cfg(debug_assertions)]
  241. let reversed_iter = (start..=end)
  242. .rev()
  243. .map(|sorted_index| dynamic_nodes[sorted_index].0);
  244. for idx in reversed_iter {
  245. let m = self.create_dynamic_node(template, &template.dynamic_nodes[idx], idx);
  246. if m > 0 {
  247. // The path is one shorter because the top node is the root
  248. let path = &template.template.get().node_paths[idx][1..];
  249. self.mutations.push(ReplacePlaceholder { m, path });
  250. }
  251. }
  252. }
  253. fn write_attrs_on_root(
  254. &mut self,
  255. attrs: &mut Peekable<impl Iterator<Item = (usize, &'static [u8])>>,
  256. root_idx: u8,
  257. root: ElementId,
  258. node: &VNode,
  259. ) {
  260. while let Some((mut attr_id, path)) =
  261. attrs.next_if(|(_, p)| p.first().copied() == Some(root_idx))
  262. {
  263. let id = self.assign_static_node_as_dynamic(path, root, node, attr_id);
  264. loop {
  265. self.write_attribute(&node.dynamic_attrs[attr_id], id);
  266. // Only push the dynamic attributes forward if they match the current path (same element)
  267. match attrs.next_if(|(_, p)| *p == path) {
  268. Some((next_attr_id, _)) => attr_id = next_attr_id,
  269. None => break,
  270. }
  271. }
  272. }
  273. }
  274. fn write_attribute(&mut self, attribute: &'b crate::Attribute<'b>, id: ElementId) {
  275. // Make sure we set the attribute's associated id
  276. attribute.mounted_element.set(id);
  277. // Safety: we promise not to re-alias this text later on after committing it to the mutation
  278. let unbounded_name: &str = unsafe { std::mem::transmute(attribute.name) };
  279. match &attribute.value {
  280. AttributeValue::Listener(_) => {
  281. self.mutations.push(NewEventListener {
  282. // all listeners start with "on"
  283. name: &unbounded_name[2..],
  284. id,
  285. })
  286. }
  287. _ => {
  288. // Safety: we promise not to re-alias this text later on after committing it to the mutation
  289. let value: BorrowedAttributeValue<'b> = (&attribute.value).into();
  290. let unbounded_value = unsafe { std::mem::transmute(value) };
  291. self.mutations.push(SetAttribute {
  292. name: unbounded_name,
  293. value: unbounded_value,
  294. ns: attribute.namespace,
  295. id,
  296. })
  297. }
  298. }
  299. }
  300. fn load_template_root(&mut self, template: &VNode, root_idx: usize) -> ElementId {
  301. // Get an ID for this root since it's a real root
  302. let this_id = self.next_root(template, root_idx);
  303. template.root_ids.set(root_idx, this_id);
  304. self.mutations.push(LoadTemplate {
  305. name: template.template.get().name,
  306. index: root_idx,
  307. id: this_id,
  308. });
  309. this_id
  310. }
  311. /// We have some dynamic attributes attached to a some node
  312. ///
  313. /// That node needs to be loaded at runtime, so we need to give it an ID
  314. ///
  315. /// If the node in question is on the stack, we just return that ID
  316. ///
  317. /// If the node is not on the stack, we create a new ID for it and assign it
  318. fn assign_static_node_as_dynamic(
  319. &mut self,
  320. path: &'static [u8],
  321. this_id: ElementId,
  322. template: &VNode,
  323. attr_id: usize,
  324. ) -> ElementId {
  325. if path.len() == 1 {
  326. return this_id;
  327. }
  328. // if attribute is on a root node, then we've already created the element
  329. // Else, it's deep in the template and we should create a new id for it
  330. let id = self.next_element(template, template.template.get().attr_paths[attr_id]);
  331. self.mutations.push(Mutation::AssignId {
  332. path: &path[1..],
  333. id,
  334. });
  335. id
  336. }
  337. /// Insert a new template into the VirtualDom's template registry
  338. pub(crate) fn register_template_first_byte_index(&mut self, mut template: Template<'static>) {
  339. // First, make sure we mark the template as seen, regardless if we process it
  340. let (path, _) = template.name.rsplit_once(':').unwrap();
  341. if let Some((_, old_template)) = self
  342. .templates
  343. .entry(path)
  344. .or_default()
  345. .iter_mut()
  346. .min_by_key(|(byte_index, _)| **byte_index)
  347. {
  348. // the byte index of the hot reloaded template could be different
  349. template.name = old_template.name;
  350. *old_template = template;
  351. } else {
  352. // This is a template without any current instances
  353. self.templates
  354. .entry(path)
  355. .or_default()
  356. .insert(usize::MAX, template);
  357. }
  358. // If it's all dynamic nodes, then we don't need to register it
  359. if !template.is_completely_dynamic() {
  360. self.mutations.templates.push(template);
  361. }
  362. }
  363. /// Insert a new template into the VirtualDom's template registry
  364. // used in conditional compilation
  365. #[allow(unused_mut)]
  366. pub(crate) fn register_template(&mut self, mut template: Template<'static>) {
  367. let (path, byte_index) = template.name.rsplit_once(':').unwrap();
  368. let byte_index = byte_index.parse::<usize>().unwrap();
  369. // First, check if we've already seen this template
  370. if self
  371. .templates
  372. .get(&path)
  373. .filter(|set| set.contains_key(&byte_index))
  374. .is_none()
  375. {
  376. // if hot reloading is enabled, then we need to check for a template that has overriten this one
  377. #[cfg(debug_assertions)]
  378. if let Some(mut new_template) = self
  379. .templates
  380. .get_mut(path)
  381. .and_then(|map| map.remove(&usize::MAX))
  382. {
  383. // the byte index of the hot reloaded template could be different
  384. new_template.name = template.name;
  385. template = new_template;
  386. }
  387. self.templates
  388. .entry(path)
  389. .or_default()
  390. .insert(byte_index, template);
  391. // If it's all dynamic nodes, then we don't need to register it
  392. if !template.is_completely_dynamic() {
  393. self.mutations.templates.push(template);
  394. }
  395. }
  396. }
  397. pub(crate) fn create_dynamic_node(
  398. &mut self,
  399. template: &'b VNode<'b>,
  400. node: &'b DynamicNode<'b>,
  401. idx: usize,
  402. ) -> usize {
  403. use DynamicNode::*;
  404. match node {
  405. Text(text) => self.create_dynamic_text(template, text, idx),
  406. Placeholder(place) => self.create_placeholder(place, template, idx),
  407. Component(component) => self.create_component_node(template, component, idx),
  408. Fragment(frag) => frag.iter().map(|child| self.create(child)).sum(),
  409. }
  410. }
  411. fn create_dynamic_text(
  412. &mut self,
  413. template: &'b VNode<'b>,
  414. text: &'b VText<'b>,
  415. idx: usize,
  416. ) -> usize {
  417. // Allocate a dynamic element reference for this text node
  418. let new_id = self.next_element(template, template.template.get().node_paths[idx]);
  419. // Make sure the text node is assigned to the correct element
  420. text.id.set(Some(new_id));
  421. // Safety: we promise not to re-alias this text later on after committing it to the mutation
  422. let value = unsafe { std::mem::transmute(text.value) };
  423. // Add the mutation to the list
  424. self.mutations.push(HydrateText {
  425. id: new_id,
  426. path: &template.template.get().node_paths[idx][1..],
  427. value,
  428. });
  429. // Since we're hydrating an existing node, we don't create any new nodes
  430. 0
  431. }
  432. pub(crate) fn create_placeholder(
  433. &mut self,
  434. placeholder: &VPlaceholder,
  435. template: &'b VNode<'b>,
  436. idx: usize,
  437. ) -> usize {
  438. // Allocate a dynamic element reference for this text node
  439. let id = self.next_element(template, template.template.get().node_paths[idx]);
  440. // Make sure the text node is assigned to the correct element
  441. placeholder.id.set(Some(id));
  442. // Assign the ID to the existing node in the template
  443. self.mutations.push(AssignId {
  444. path: &template.template.get().node_paths[idx][1..],
  445. id,
  446. });
  447. // Since the placeholder is already in the DOM, we don't create any new nodes
  448. 0
  449. }
  450. pub(super) fn create_component_node(
  451. &mut self,
  452. template: &'b VNode<'b>,
  453. component: &'b VComponent<'b>,
  454. idx: usize,
  455. ) -> usize {
  456. use RenderReturn::*;
  457. // Load up a ScopeId for this vcomponent
  458. let scope = self.load_scope_from_vcomponent(component);
  459. component.scope.set(Some(scope));
  460. match unsafe { self.run_scope(scope).extend_lifetime_ref() } {
  461. Ready(t) => self.mount_component(scope, template, t, idx),
  462. Aborted(t) => self.mount_aborted(template, t),
  463. Pending(_) => self.mount_async(template, idx, scope),
  464. }
  465. }
  466. /// Load a scope from a vcomponent. If the props don't exist, that means the component is currently "live"
  467. fn load_scope_from_vcomponent(&mut self, component: &VComponent) -> ScopeId {
  468. component
  469. .props
  470. .take()
  471. .map(|props| {
  472. let unbounded_props: Box<dyn AnyProps> = unsafe { std::mem::transmute(props) };
  473. self.new_scope(unbounded_props, component.name).id
  474. })
  475. .unwrap_or_else(|| component.scope.get().unwrap())
  476. }
  477. fn mount_component(
  478. &mut self,
  479. scope: ScopeId,
  480. parent: &'b VNode<'b>,
  481. new: &'b VNode<'b>,
  482. idx: usize,
  483. ) -> usize {
  484. // Keep track of how many mutations are in the buffer in case we need to split them out if a suspense boundary
  485. // is encountered
  486. let mutations_to_this_point = self.mutations.edits.len();
  487. // Create the component's root element
  488. let created = self.create_scope(scope, new);
  489. // If there are no suspense leaves below us, then just don't bother checking anything suspense related
  490. if self.collected_leaves.is_empty() {
  491. return created;
  492. }
  493. // If running the scope has collected some leaves and *this* component is a boundary, then handle the suspense
  494. let boundary = match self.scopes[scope].has_context::<Rc<SuspenseContext>>() {
  495. Some(boundary) => boundary,
  496. _ => return created,
  497. };
  498. // Since this is a boundary, use its placeholder within the template as the placeholder for the suspense tree
  499. let new_id = self.next_element(new, parent.template.get().node_paths[idx]);
  500. // Now connect everything to the boundary
  501. self.scopes[scope].placeholder.set(Some(new_id));
  502. // This involves breaking off the mutations to this point, and then creating a new placeholder for the boundary
  503. // Note that we break off dynamic mutations only - since static mutations aren't rendered immediately
  504. let split_off = unsafe {
  505. std::mem::transmute::<Vec<Mutation>, Vec<Mutation>>(
  506. self.mutations.edits.split_off(mutations_to_this_point),
  507. )
  508. };
  509. boundary.mutations.borrow_mut().edits.extend(split_off);
  510. boundary.created_on_stack.set(created);
  511. boundary
  512. .waiting_on
  513. .borrow_mut()
  514. .extend(self.collected_leaves.drain(..));
  515. // Now assign the placeholder in the DOM
  516. self.mutations.push(AssignId {
  517. id: new_id,
  518. path: &parent.template.get().node_paths[idx][1..],
  519. });
  520. 0
  521. }
  522. fn mount_aborted(&mut self, parent: &'b VNode<'b>, placeholder: &VPlaceholder) -> usize {
  523. let id = self.next_element(parent, &[]);
  524. self.mutations.push(Mutation::CreatePlaceholder { id });
  525. placeholder.id.set(Some(id));
  526. 1
  527. }
  528. /// Take the rendered nodes from a component and handle them if they were async
  529. ///
  530. /// IE simply assign an ID to the placeholder
  531. fn mount_async(&mut self, template: &VNode, idx: usize, scope: ScopeId) -> usize {
  532. let new_id = self.next_element(template, template.template.get().node_paths[idx]);
  533. // Set the placeholder of the scope
  534. self.scopes[scope].placeholder.set(Some(new_id));
  535. // Since the placeholder is already in the DOM, we don't create any new nodes
  536. self.mutations.push(AssignId {
  537. id: new_id,
  538. path: &template.template.get().node_paths[idx][1..],
  539. });
  540. 0
  541. }
  542. fn set_slot(
  543. &mut self,
  544. template: &'b VNode<'b>,
  545. slot: &'b Cell<Option<ElementId>>,
  546. id: usize,
  547. ) -> ElementId {
  548. let id = self.next_element(template, template.template.get().node_paths[id]);
  549. slot.set(Some(id));
  550. id
  551. }
  552. }
  553. fn collect_dyn_node_range(
  554. dynamic_nodes: &mut Peekable<impl Iterator<Item = ((usize, usize), &'static [u8])>>,
  555. root_idx: u8,
  556. ) -> Option<(usize, usize)> {
  557. let start = match dynamic_nodes.peek() {
  558. Some(((_, idx), [first, ..])) if *first == root_idx => *idx,
  559. _ => return None,
  560. };
  561. let mut end = start;
  562. while let Some(((_, idx), p)) =
  563. dynamic_nodes.next_if(|(_, p)| matches!(p, [idx, ..] if *idx == root_idx))
  564. {
  565. if p.len() == 1 {
  566. continue;
  567. }
  568. end = idx;
  569. }
  570. Some((start, end))
  571. }