scope_arena.rs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. use crate::{
  2. any_props::AnyProps,
  3. bump_frame::BumpFrame,
  4. innerlude::{DirtyScope, VPlaceholder},
  5. innerlude::{SuspenseId, SuspenseLeaf},
  6. nodes::RenderReturn,
  7. scheduler::ArcWake,
  8. scopes::{ScopeId, ScopeState},
  9. virtual_dom::VirtualDom,
  10. };
  11. use bumpalo::Bump;
  12. use futures_util::FutureExt;
  13. use std::{
  14. mem,
  15. pin::Pin,
  16. rc::Rc,
  17. sync::Arc,
  18. task::{Context, Poll},
  19. };
  20. impl VirtualDom {
  21. pub(super) fn new_scope(
  22. &mut self,
  23. props: Box<dyn AnyProps<'static>>,
  24. name: &'static str,
  25. ) -> &ScopeState {
  26. let parent = self.acquire_current_scope_raw();
  27. let entry = self.scopes.vacant_entry();
  28. let height = unsafe { parent.map(|f| (*f).height + 1).unwrap_or(0) };
  29. let id = ScopeId(entry.key());
  30. entry.insert(Box::new(ScopeState {
  31. parent,
  32. id,
  33. height,
  34. name,
  35. props: Some(props),
  36. tasks: self.scheduler.clone(),
  37. placeholder: Default::default(),
  38. node_arena_1: BumpFrame::new(0),
  39. node_arena_2: BumpFrame::new(0),
  40. spawned_tasks: Default::default(),
  41. render_cnt: Default::default(),
  42. hook_arena: Default::default(),
  43. hook_list: Default::default(),
  44. hook_idx: Default::default(),
  45. shared_contexts: Default::default(),
  46. borrowed_props: Default::default(),
  47. listeners: Default::default(),
  48. }))
  49. }
  50. fn acquire_current_scope_raw(&mut self) -> Option<*mut ScopeState> {
  51. self.scope_stack
  52. .last()
  53. .copied()
  54. .and_then(|id| self.scopes.get_mut(id.0).map(|f| f.as_mut() as *mut _))
  55. }
  56. pub(crate) fn run_scope(&mut self, scope_id: ScopeId) -> &RenderReturn {
  57. // Cycle to the next frame and then reset it
  58. // This breaks any latent references, invalidating every pointer referencing into it.
  59. // Remove all the outdated listeners
  60. self.ensure_drop_safety(scope_id);
  61. let mut new_nodes = unsafe {
  62. let scope = self.scopes[scope_id.0].as_mut();
  63. // if this frame hasn't been intialized yet, we can guess the size of the next frame to be more efficient
  64. if scope.previous_frame().bump.allocated_bytes() == 0 {
  65. scope.previous_frame_mut().bump =
  66. Bump::with_capacity(scope.current_frame().bump.allocated_bytes());
  67. } else {
  68. scope.previous_frame_mut().bump.reset();
  69. }
  70. // Make sure to reset the hook counter so we give out hooks in the right order
  71. scope.hook_idx.set(0);
  72. // safety: due to how we traverse the tree, we know that the scope is not currently aliased
  73. let props: &dyn AnyProps = scope.props.as_ref().unwrap().as_ref();
  74. let props: &dyn AnyProps = mem::transmute(props);
  75. props.render(scope).extend_lifetime()
  76. };
  77. // immediately resolve futures that can be resolved
  78. if let RenderReturn::Async(task) = &mut new_nodes {
  79. let mut leaves = self.scheduler.leaves.borrow_mut();
  80. let entry = leaves.vacant_entry();
  81. let suspense_id = SuspenseId(entry.key());
  82. let leaf = Arc::new(SuspenseLeaf {
  83. scope_id,
  84. task: task.as_mut(),
  85. id: suspense_id,
  86. tx: self.scheduler.sender.clone(),
  87. notified: Default::default(),
  88. });
  89. let waker = leaf.waker();
  90. let mut cx = Context::from_waker(&waker);
  91. // safety: the task is already pinned in the bump arena
  92. let mut pinned = unsafe { Pin::new_unchecked(task.as_mut()) };
  93. // Keep polling until either we get a value or the future is not ready
  94. loop {
  95. match pinned.poll_unpin(&mut cx) {
  96. // If nodes are produced, then set it and we can break
  97. Poll::Ready(nodes) => {
  98. new_nodes = match nodes {
  99. Some(nodes) => RenderReturn::Ready(nodes),
  100. None => RenderReturn::default(),
  101. };
  102. break;
  103. }
  104. // If no nodes are produced but the future woke up immediately, then try polling it again
  105. // This circumvents things like yield_now, but is important is important when rendering
  106. // components that are just a stream of immediately ready futures
  107. _ if leaf.notified.get() => {
  108. leaf.notified.set(false);
  109. continue;
  110. }
  111. // If no nodes are produced, then we need to wait for the future to be woken up
  112. // Insert the future into fiber leaves and break
  113. _ => {
  114. entry.insert(leaf);
  115. self.collected_leaves.push(suspense_id);
  116. break;
  117. }
  118. };
  119. }
  120. };
  121. let scope = &self.scopes[scope_id.0];
  122. // We write on top of the previous frame and then make it the current by pushing the generation forward
  123. let frame = scope.previous_frame();
  124. // set the new head of the bump frame
  125. let allocated = &*frame.bump.alloc(new_nodes);
  126. frame.node.set(allocated);
  127. // And move the render generation forward by one
  128. scope.render_cnt.set(scope.render_cnt.get() + 1);
  129. // remove this scope from dirty scopes
  130. self.dirty_scopes.remove(&DirtyScope {
  131. height: scope.height,
  132. id: scope.id,
  133. });
  134. // rebind the lifetime now that its stored internally
  135. unsafe { allocated.extend_lifetime_ref() }
  136. }
  137. }