create.rs 19 KB

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