create.rs 20 KB

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