create.rs 21 KB

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