create.rs 20 KB

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