scope_arena.rs 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. use crate::{
  2. any_props::AnyProps,
  3. bump_frame::BumpFrame,
  4. innerlude::DirtyScope,
  5. nodes::RenderReturn,
  6. scopes::{ScopeId, ScopeState},
  7. virtual_dom::VirtualDom,
  8. };
  9. impl VirtualDom {
  10. pub(super) fn new_scope(
  11. &mut self,
  12. props: Box<dyn AnyProps<'static>>,
  13. name: &'static str,
  14. ) -> &ScopeState {
  15. let parent = self.acquire_current_scope_raw();
  16. let entry = self.scopes.vacant_entry();
  17. let height = unsafe { parent.map(|f| (*f).height + 1).unwrap_or(0) };
  18. let id = entry.key();
  19. entry.insert(ScopeState {
  20. parent,
  21. id,
  22. height,
  23. name,
  24. props: Some(props),
  25. tasks: self.scheduler.clone(),
  26. node_arena_1: BumpFrame::new(0),
  27. node_arena_2: BumpFrame::new(0),
  28. spawned_tasks: Default::default(),
  29. suspended: Default::default(),
  30. render_cnt: Default::default(),
  31. hooks: Default::default(),
  32. hook_idx: Default::default(),
  33. shared_contexts: Default::default(),
  34. borrowed_props: Default::default(),
  35. attributes_to_drop: Default::default(),
  36. })
  37. }
  38. fn acquire_current_scope_raw(&self) -> Option<*const ScopeState> {
  39. let id = self.scope_stack.last().copied()?;
  40. let scope = self.scopes.get(id)?;
  41. Some(scope)
  42. }
  43. pub(crate) fn run_scope(&mut self, scope_id: ScopeId) -> &RenderReturn {
  44. // Cycle to the next frame and then reset it
  45. // This breaks any latent references, invalidating every pointer referencing into it.
  46. // Remove all the outdated listeners
  47. self.ensure_drop_safety(scope_id);
  48. let new_nodes = unsafe {
  49. self.scopes[scope_id].previous_frame().bump_mut().reset();
  50. let scope = &self.scopes[scope_id];
  51. scope.suspended.set(false);
  52. scope.hook_idx.set(0);
  53. // safety: due to how we traverse the tree, we know that the scope is not currently aliased
  54. let props: &dyn AnyProps = scope.props.as_ref().unwrap().as_ref();
  55. let props: &dyn AnyProps = std::mem::transmute(props);
  56. props.render(scope).extend_lifetime()
  57. };
  58. let scope = &self.scopes[scope_id];
  59. // We write on top of the previous frame and then make it the current by pushing the generation forward
  60. let frame = scope.previous_frame();
  61. // set the new head of the bump frame
  62. let allocated = &*frame.bump().alloc(new_nodes);
  63. frame.node.set(allocated);
  64. // And move the render generation forward by one
  65. scope.render_cnt.set(scope.render_cnt.get() + 1);
  66. // remove this scope from dirty scopes
  67. self.dirty_scopes.remove(&DirtyScope {
  68. height: scope.height,
  69. id: scope.id,
  70. });
  71. if scope.suspended.get() {
  72. self.suspended_scopes.insert(scope.id);
  73. } else if !self.suspended_scopes.is_empty() {
  74. _ = self.suspended_scopes.remove(&scope.id);
  75. }
  76. // rebind the lifetime now that its stored internally
  77. unsafe { allocated.extend_lifetime_ref() }
  78. }
  79. }