scope_arena.rs 5.3 KB

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