create.rs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. use std::pin::Pin;
  2. use crate::factory::{FiberLeaf, RenderReturn};
  3. use crate::innerlude::{Renderer, SuspenseContext};
  4. use crate::mutations::Mutation;
  5. use crate::mutations::Mutation::*;
  6. use crate::nodes::VNode;
  7. use crate::nodes::{DynamicNode, TemplateNode};
  8. use crate::virtual_dom::VirtualDom;
  9. use crate::{AttributeValue, Element, ElementId, TemplateAttribute};
  10. use bumpalo::boxed::Box as BumpBox;
  11. use futures_util::Future;
  12. impl VirtualDom {
  13. /// Create this template and write its mutations
  14. pub fn create<'a>(&mut self, mutations: &mut Renderer<'a>, template: &'a VNode<'a>) -> usize {
  15. // The best renderers will have templates prehydrated
  16. // Just in case, let's create the template using instructions anyways
  17. if !self.templates.contains_key(&template.template.id) {
  18. for node in template.template.roots {
  19. let mutations = &mut mutations.template_mutations;
  20. self.create_static_node(mutations, template, node);
  21. }
  22. mutations.template_mutations.push(SaveTemplate {
  23. name: template.template.id,
  24. m: template.template.roots.len(),
  25. });
  26. self.templates
  27. .insert(template.template.id, template.template.clone());
  28. }
  29. // Walk the roots backwards, creating nodes and assigning IDs
  30. // todo: adjust dynamic nodes to be in the order of roots and then leaves (ie BFS)
  31. let mut dynamic_attrs = template.template.attr_paths.iter().enumerate().peekable();
  32. let mut dynamic_nodes = template.template.node_paths.iter().enumerate().peekable();
  33. let mut on_stack = 0;
  34. for (root_idx, root) in template.template.roots.iter().enumerate() {
  35. on_stack += match root {
  36. TemplateNode::Element { .. } | TemplateNode::Text(_) => {
  37. mutations.push(LoadTemplate {
  38. name: template.template.id,
  39. index: root_idx,
  40. });
  41. 1
  42. }
  43. TemplateNode::Dynamic(id) => {
  44. self.create_dynamic_node(mutations, template, &template.dynamic_nodes[*id], *id)
  45. }
  46. TemplateNode::DynamicText { .. } => 1,
  47. };
  48. // we're on top of a node that has a dynamic attribute for a descendant
  49. // Set that attribute now before the stack gets in a weird state
  50. while let Some((mut attr_id, path)) =
  51. dynamic_attrs.next_if(|(_, p)| p[0] == root_idx as u8)
  52. {
  53. let id = self.next_element(template);
  54. mutations.push(AssignId {
  55. path: &path[1..],
  56. id,
  57. });
  58. // set any future attrs with the same path (ie same element)
  59. loop {
  60. let attr = &template.dynamic_attrs[attr_id];
  61. attr.mounted_element.set(id);
  62. match attr.value {
  63. AttributeValue::Text(value) => mutations.push(SetAttribute {
  64. name: attr.name,
  65. value,
  66. id,
  67. }),
  68. AttributeValue::Listener(_) => {}
  69. AttributeValue::Float(_) => todo!(),
  70. AttributeValue::Int(_) => todo!(),
  71. AttributeValue::Bool(_) => todo!(),
  72. AttributeValue::Any(_) => todo!(),
  73. AttributeValue::None => todo!(),
  74. }
  75. if let Some((next_attr_id, _)) = dynamic_attrs.next_if(|(_, p)| *p == path) {
  76. attr_id = next_attr_id
  77. } else {
  78. break;
  79. }
  80. }
  81. }
  82. // We're on top of a node that has a dynamic child for a descendant
  83. // Skip any node that's a root
  84. while let Some((idx, path)) =
  85. dynamic_nodes.next_if(|(_, p)| p.len() > 1 && p[0] == root_idx as u8)
  86. {
  87. let node = &template.dynamic_nodes[idx];
  88. let m = self.create_dynamic_node(mutations, template, node, idx);
  89. if m > 0 {
  90. mutations.push(ReplacePlaceholder {
  91. m,
  92. path: &path[1..],
  93. });
  94. }
  95. }
  96. }
  97. on_stack
  98. }
  99. pub fn create_static_node<'a>(
  100. &mut self,
  101. mutations: &mut Vec<Mutation<'a>>,
  102. template: &'a VNode<'a>,
  103. node: &'a TemplateNode<'static>,
  104. ) {
  105. match *node {
  106. // Todo: create the children's template
  107. TemplateNode::Dynamic(_) => mutations.push(CreatePlaceholder { id: ElementId(0) }),
  108. TemplateNode::Text(value) => mutations.push(CreateText { value }),
  109. TemplateNode::DynamicText { .. } => mutations.push(CreateText {
  110. value: "placeholder",
  111. }),
  112. TemplateNode::Element {
  113. attrs,
  114. children,
  115. namespace,
  116. tag,
  117. } => {
  118. let id = self.next_element(template);
  119. mutations.push(CreateElement {
  120. name: tag,
  121. namespace,
  122. id,
  123. });
  124. mutations.extend(attrs.into_iter().filter_map(|attr| match attr {
  125. TemplateAttribute::Static { name, value, .. } => {
  126. Some(SetAttribute { name, value, id })
  127. }
  128. _ => None,
  129. }));
  130. children
  131. .into_iter()
  132. .for_each(|child| self.create_static_node(mutations, template, child));
  133. mutations.push(AppendChildren { m: children.len() })
  134. }
  135. }
  136. }
  137. pub fn create_dynamic_node<'a>(
  138. &mut self,
  139. mutations: &mut Renderer<'a>,
  140. template: &'a VNode<'a>,
  141. node: &'a DynamicNode<'a>,
  142. idx: usize,
  143. ) -> usize {
  144. match &node {
  145. DynamicNode::Text { id, value } => {
  146. let new_id = self.next_element(template);
  147. id.set(new_id);
  148. mutations.push(HydrateText {
  149. id: new_id,
  150. path: &template.template.node_paths[idx][1..],
  151. value,
  152. });
  153. 1
  154. }
  155. DynamicNode::Component {
  156. props, placeholder, ..
  157. } => {
  158. let id = self.new_scope(unsafe { std::mem::transmute(props.get()) });
  159. let render_ret = self.run_scope(id);
  160. let render_ret: &mut RenderReturn = unsafe { std::mem::transmute(render_ret) };
  161. // if boundary or subtree, start working on a new stack of mutations
  162. match render_ret {
  163. RenderReturn::Sync(None) | RenderReturn::Async(_) => {
  164. let new_id = self.next_element(template);
  165. placeholder.set(Some(new_id));
  166. self.scopes[id.0].placeholder.set(Some(new_id));
  167. mutations.push(AssignId {
  168. id: new_id,
  169. path: &template.template.node_paths[idx][1..],
  170. });
  171. 0
  172. }
  173. RenderReturn::Sync(Some(template)) => {
  174. let mutations_to_this_point = mutations.len();
  175. self.scope_stack.push(id);
  176. let mut created = self.create(mutations, template);
  177. self.scope_stack.pop();
  178. if !self.waiting_on.is_empty() {
  179. if let Some(boundary) =
  180. self.scopes[id.0].has_context::<SuspenseContext>()
  181. {
  182. let mut boundary_mut = boundary.borrow_mut();
  183. let split_off = mutations.split_off(mutations_to_this_point);
  184. let split_off = unsafe { std::mem::transmute(split_off) };
  185. println!("SPLIT OFF: {:#?}", split_off);
  186. boundary_mut.mutations.mutations = split_off;
  187. boundary_mut.waiting_on.extend(self.waiting_on.drain(..));
  188. // Since this is a boundary, use it as a placeholder
  189. let new_id = self.next_element(template);
  190. placeholder.set(Some(new_id));
  191. self.scopes[id.0].placeholder.set(Some(new_id));
  192. mutations.push(AssignId {
  193. id: new_id,
  194. path: &template.template.node_paths[idx][1..],
  195. });
  196. created = 0;
  197. }
  198. }
  199. // handle any waiting on futures accumulated by async calls down the tree
  200. // if this is a boundary, we split off the tree
  201. created
  202. }
  203. }
  204. }
  205. DynamicNode::Fragment(children) => children
  206. .iter()
  207. .fold(0, |acc, child| acc + self.create(mutations, child)),
  208. DynamicNode::Placeholder(_) => {
  209. let id = self.next_element(template);
  210. mutations.push(CreatePlaceholder { id });
  211. 1
  212. }
  213. }
  214. }
  215. }