123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- use std::cell::{Cell, Ref, RefCell};
- use crate::{innerlude::Scheduler, scope_context::ScopeContext, scopes::ScopeId};
- use std::rc::Rc;
- thread_local! {
- static RUNTIMES: RefCell<Vec<Rc<Runtime>>> = RefCell::new(vec![]);
- }
- /// Pushes a new scope onto the stack
- pub(crate) fn push_runtime(runtime: Rc<Runtime>) {
- RUNTIMES.with(|stack| stack.borrow_mut().push(runtime));
- }
- /// Pops a scope off the stack
- pub(crate) fn pop_runtime() {
- RUNTIMES.with(|stack| stack.borrow_mut().pop());
- }
- /// Runs a function with the current runtime
- pub(crate) fn with_runtime<F, R>(f: F) -> Option<R>
- where
- F: FnOnce(&Runtime) -> R,
- {
- RUNTIMES.with(|stack| {
- let stack = stack.borrow();
- stack.last().map(|r| f(r))
- })
- }
- /// Runs a function with the current scope
- pub(crate) fn with_current_scope<F, R>(f: F) -> Option<R>
- where
- F: FnOnce(&ScopeContext) -> R,
- {
- with_runtime(|runtime| {
- runtime
- .current_scope_id()
- .and_then(|scope| runtime.get_context(scope).map(|sc| f(&sc)))
- })
- .flatten()
- }
- /// A global runtime that is shared across all scopes that provides the async runtime and context API
- pub struct Runtime {
- pub(crate) scope_contexts: RefCell<Vec<Option<ScopeContext>>>,
- pub(crate) scheduler: Rc<Scheduler>,
- // We use this to track the current scope
- pub(crate) scope_stack: RefCell<Vec<ScopeId>>,
- pub(crate) rendering: Cell<bool>,
- }
- impl Runtime {
- pub(crate) fn new(scheduler: Rc<Scheduler>) -> Rc<Self> {
- Rc::new(Self {
- scheduler,
- scope_contexts: Default::default(),
- scope_stack: Default::default(),
- rendering: Cell::new(true),
- })
- }
- /// Get the current runtime
- pub fn current() -> Option<Rc<Self>> {
- RUNTIMES.with(|stack| stack.borrow().last().cloned())
- }
- /// Create a scope context. This slab is synchronized with the scope slab.
- pub(crate) fn create_context_at(&self, id: ScopeId, context: ScopeContext) {
- let mut contexts = self.scope_contexts.borrow_mut();
- if contexts.len() <= id.0 {
- contexts.resize_with(id.0 + 1, Default::default);
- }
- contexts[id.0] = Some(context);
- }
- pub(crate) fn remove_context(&self, id: ScopeId) {
- self.scope_contexts.borrow_mut()[id.0] = None;
- }
- /// Get the current scope id
- pub(crate) fn current_scope_id(&self) -> Option<ScopeId> {
- self.scope_stack.borrow().last().copied()
- }
- /// Call this function with the current scope set to the given scope
- ///
- /// Useful in a limited number of scenarios, not public.
- pub(crate) fn with_scope<O>(&self, id: ScopeId, f: impl FnOnce() -> O) -> O {
- self.scope_stack.borrow_mut().push(id);
- let o = f();
- self.scope_stack.borrow_mut().pop();
- o
- }
- /// Get the context for any scope given its ID
- ///
- /// This is useful for inserting or removing contexts from a scope, or rendering out its root node
- pub(crate) fn get_context(&self, id: ScopeId) -> Option<Ref<'_, ScopeContext>> {
- Ref::filter_map(self.scope_contexts.borrow(), |contexts| {
- contexts.get(id.0).and_then(|f| f.as_ref())
- })
- .ok()
- }
- }
- /// A guard for a new runtime. This must be used to override the current runtime when importing components from a dynamic library that has it's own runtime.
- ///
- /// ```rust
- /// use dioxus::prelude::*;
- ///
- /// fn main() {
- /// let virtual_dom = VirtualDom::new(app);
- /// }
- ///
- /// fn app(cx: Scope) -> Element {
- /// render!{ Component { runtime: Runtime::current().unwrap() } }
- /// }
- ///
- /// // In a dynamic library
- /// #[derive(Props)]
- /// struct ComponentProps {
- /// runtime: std::rc::Rc<Runtime>,
- /// }
- ///
- /// impl PartialEq for ComponentProps {
- /// fn eq(&self, _other: &Self) -> bool {
- /// true
- /// }
- /// }
- ///
- /// # #[allow(non_snake_case)]
- /// fn Component(cx: Scope<ComponentProps>) -> Element {
- /// cx.use_hook(|| RuntimeGuard::new(cx.props.runtime.clone()));
- ///
- /// render! { div {} }
- /// }
- /// ```
- pub struct RuntimeGuard(Rc<Runtime>);
- impl RuntimeGuard {
- /// Create a new runtime guard that sets the current Dioxus runtime. The runtime will be reset when the guard is dropped
- pub fn new(runtime: Rc<Runtime>) -> Self {
- push_runtime(runtime.clone());
- Self(runtime)
- }
- /// Run a function with a given runtime and scope in context
- pub fn with<O>(runtime: Rc<Runtime>, scope: Option<ScopeId>, f: impl FnOnce() -> O) -> O {
- let guard = Self::new(runtime.clone());
- let o = match scope {
- Some(scope) => Runtime::with_scope(&runtime, scope, f),
- None => f(),
- };
- drop(guard);
- o
- }
- }
- impl Drop for RuntimeGuard {
- fn drop(&mut self) {
- pop_runtime();
- }
- }
|