scope.rs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. use crate::innerlude::*;
  2. use bumpalo::boxed::Box as BumpBox;
  3. use futures_channel::mpsc::UnboundedSender;
  4. use fxhash::FxHashSet;
  5. use std::{
  6. any::{Any, TypeId},
  7. borrow::BorrowMut,
  8. cell::{Cell, RefCell},
  9. collections::{HashMap, HashSet},
  10. future::Future,
  11. pin::Pin,
  12. rc::Rc,
  13. };
  14. /// Every component in Dioxus is represented by a `Scope`.
  15. ///
  16. /// Scopes contain the state for hooks, the component's props, and other lifecycle information.
  17. ///
  18. /// Scopes are allocated in a generational arena. As components are mounted/unmounted, they will replace slots of dead components.
  19. /// The actual contents of the hooks, though, will be allocated with the standard allocator. These should not allocate as frequently.
  20. ///
  21. /// We expose the `Scope` type so downstream users can traverse the Dioxus VirtualDOM for whatever
  22. /// usecase they might have.
  23. pub struct Scope {
  24. // Book-keeping about our spot in the arena
  25. pub(crate) parent_idx: Option<ScopeId>,
  26. pub(crate) our_arena_idx: ScopeId,
  27. pub(crate) height: u32,
  28. pub(crate) descendents: RefCell<FxHashSet<ScopeId>>,
  29. // Nodes
  30. // an internal, highly efficient storage of vnodes
  31. // lots of safety condsiderations
  32. pub(crate) frames: ActiveFrame,
  33. pub(crate) caller: Rc<WrappedCaller>,
  34. pub(crate) child_nodes: ScopeChildren<'static>,
  35. pub(crate) pending_garbage: RefCell<Vec<*const VNode<'static>>>,
  36. // Listeners
  37. pub(crate) listeners: RefCell<Vec<*const Listener<'static>>>,
  38. pub(crate) borrowed_props: RefCell<Vec<*const VComponent<'static>>>,
  39. pub(crate) suspended_nodes: RefCell<HashMap<u64, *const VNode<'static>>>,
  40. // State
  41. pub(crate) hooks: HookList,
  42. pub(crate) shared_contexts: RefCell<HashMap<TypeId, Rc<dyn Any>>>,
  43. pub(crate) memoized_updater: Rc<dyn Fn() + 'static>,
  44. pub(crate) shared: EventChannel,
  45. }
  46. // The type of closure that wraps calling components
  47. pub type WrappedCaller = dyn for<'b> Fn(&'b Scope) -> DomTree<'b>;
  48. /// The type of task that gets sent to the task scheduler
  49. /// Submitting a fiber task returns a handle to that task, which can be used to wake up suspended nodes
  50. pub type FiberTask = Pin<Box<dyn Future<Output = ScopeId>>>;
  51. impl Scope {
  52. // we are being created in the scope of an existing component (where the creator_node lifetime comes into play)
  53. // we are going to break this lifetime by force in order to save it on ourselves.
  54. // To make sure that the lifetime isn't truly broken, we receive a Weak RC so we can't keep it around after the parent dies.
  55. // This should never happen, but is a good check to keep around
  56. //
  57. // Scopes cannot be made anywhere else except for this file
  58. // Therefore, their lifetimes are connected exclusively to the virtual dom
  59. pub fn new<'creator_node>(
  60. caller: Rc<WrappedCaller>,
  61. arena_idx: ScopeId,
  62. parent: Option<ScopeId>,
  63. height: u32,
  64. child_nodes: ScopeChildren,
  65. shared: EventChannel,
  66. ) -> Self {
  67. let child_nodes = unsafe { child_nodes.extend_lifetime() };
  68. let up = shared.schedule_any_immediate.clone();
  69. let memoized_updater = Rc::new(move || up(arena_idx));
  70. Self {
  71. memoized_updater,
  72. shared,
  73. child_nodes,
  74. caller,
  75. parent_idx: parent,
  76. our_arena_idx: arena_idx,
  77. height,
  78. frames: ActiveFrame::new(),
  79. hooks: Default::default(),
  80. suspended_nodes: Default::default(),
  81. shared_contexts: Default::default(),
  82. listeners: Default::default(),
  83. borrowed_props: Default::default(),
  84. descendents: Default::default(),
  85. pending_garbage: Default::default(),
  86. }
  87. }
  88. pub(crate) fn update_scope_dependencies<'creator_node>(
  89. &mut self,
  90. caller: Rc<WrappedCaller>,
  91. child_nodes: ScopeChildren,
  92. ) {
  93. self.caller = caller;
  94. let child_nodes = unsafe { child_nodes.extend_lifetime() };
  95. self.child_nodes = child_nodes;
  96. }
  97. pub(crate) fn run_scope<'sel>(&'sel mut self) -> Result<()> {
  98. // Cycle to the next frame and then reset it
  99. // This breaks any latent references, invalidating every pointer referencing into it.
  100. // Remove all the outdated listeners
  101. self.ensure_drop_safety();
  102. // Safety:
  103. // - We dropped the listeners, so no more &mut T can be used while these are held
  104. // - All children nodes that rely on &mut T are replaced with a new reference
  105. unsafe { self.hooks.reset() };
  106. // Safety:
  107. // - We've dropped all references to the wip bump frame
  108. unsafe { self.frames.reset_wip_frame() };
  109. // Cast the caller ptr from static to one with our own reference
  110. let render: &WrappedCaller = self.caller.as_ref();
  111. match render(self) {
  112. None => {
  113. // the user's component failed. We avoid cycling to the next frame
  114. log::error!("Running your component failed! It will no longer receive events.");
  115. Err(Error::ComponentFailed)
  116. }
  117. Some(new_head) => {
  118. // the user's component succeeded. We can safely cycle to the next frame
  119. self.frames.wip_frame_mut().head_node = unsafe { std::mem::transmute(new_head) };
  120. self.frames.cycle_frame();
  121. log::debug!("Successfully rendered component");
  122. Ok(())
  123. }
  124. }
  125. }
  126. /// This method cleans up any references to data held within our hook list. This prevents mutable aliasing from
  127. /// causuing UB in our tree.
  128. ///
  129. /// This works by cleaning up our references from the bottom of the tree to the top. The directed graph of components
  130. /// essentially forms a dependency tree that we can traverse from the bottom to the top. As we traverse, we remove
  131. /// any possible references to the data in the hook list.
  132. ///
  133. /// Refrences to hook data can only be stored in listeners and component props. During diffing, we make sure to log
  134. /// all listeners and borrowed props so we can clear them here.
  135. fn ensure_drop_safety(&mut self) {
  136. // make sure all garabge is collected before trying to proceed with anything else
  137. debug_assert!(
  138. self.pending_garbage.borrow().is_empty(),
  139. "clean up your garabge please"
  140. );
  141. todo!("arch changes");
  142. // // make sure we drop all borrowed props manually to guarantee that their drop implementation is called before we
  143. // // run the hooks (which hold an &mut Referrence)
  144. // // right now, we don't drop
  145. // // let vdom = &self.vdom;
  146. // self.borrowed_props
  147. // .get_mut()
  148. // .drain(..)
  149. // .map(|li| unsafe { &*li })
  150. // .for_each(|comp| {
  151. // // First drop the component's undropped references
  152. // let scope_id = comp.ass_scope.get().unwrap();
  153. // let scope = unsafe { vdom.get_scope_mut(scope_id) }.unwrap();
  154. // scope.ensure_drop_safety();
  155. // // Now, drop our own reference
  156. // let mut dropper = comp.drop_props.borrow_mut().take().unwrap();
  157. // dropper();
  158. // });
  159. // // Now that all the references are gone, we can safely drop our own references in our listeners.
  160. // self.listeners
  161. // .get_mut()
  162. // .drain(..)
  163. // .map(|li| unsafe { &*li })
  164. // .for_each(|listener| {
  165. // listener.callback.borrow_mut().take();
  166. // });
  167. }
  168. // A safe wrapper around calling listeners
  169. //
  170. //
  171. pub(crate) fn call_listener(
  172. &mut self,
  173. event: SyntheticEvent,
  174. element: ElementId,
  175. ) -> Result<()> {
  176. let listners = self.listeners.borrow_mut();
  177. let raw_listener = listners.iter().find(|lis| {
  178. let search = unsafe { &***lis };
  179. let search_id = search.mounted_node.get();
  180. // this assumes the node might not be mounted - should we assume that though?
  181. match search_id.map(|f| f == element) {
  182. Some(same) => same,
  183. None => false,
  184. }
  185. });
  186. if let Some(raw_listener) = raw_listener {
  187. let listener = unsafe { &**raw_listener };
  188. let mut cb = listener.callback.borrow_mut();
  189. if let Some(cb) = cb.as_mut() {
  190. (cb)(event);
  191. }
  192. } else {
  193. log::warn!("An event was triggered but there was no listener to handle it");
  194. }
  195. Ok(())
  196. }
  197. pub fn root(&self) -> &VNode {
  198. self.frames.fin_head()
  199. }
  200. pub fn child_nodes<'a>(&'a self) -> ScopeChildren {
  201. unsafe { self.child_nodes.unextend_lfetime() }
  202. }
  203. pub fn consume_garbage(&self) -> Vec<&VNode> {
  204. self.pending_garbage
  205. .borrow_mut()
  206. .drain(..)
  207. .map(|node| {
  208. // safety: scopes cannot cycle without their garbage being collected. these nodes are safe
  209. let node: &VNode<'static> = unsafe { &*node };
  210. let node: &VNode = unsafe { std::mem::transmute(node) };
  211. node
  212. })
  213. .collect::<Vec<_>>()
  214. }
  215. }