freya_core/
current_context.rs

1use std::{
2    cell::RefCell,
3    rc::Rc,
4    sync::atomic::AtomicU64,
5};
6
7use rustc_hash::FxHashMap;
8
9use crate::{
10    prelude::{
11        Task,
12        TaskId,
13    },
14    reactive_context::ReactiveContext,
15    runner::Message,
16    scope::ScopeStorage,
17    scope_id::ScopeId,
18};
19
20// TODO: rendering flag.
21pub struct CurrentContext {
22    pub scope_id: ScopeId,
23    pub scopes_storages: Rc<RefCell<FxHashMap<ScopeId, ScopeStorage>>>,
24
25    pub tasks: Rc<RefCell<FxHashMap<TaskId, Rc<RefCell<Task>>>>>,
26    pub task_id_counter: Rc<AtomicU64>,
27    pub sender: futures_channel::mpsc::UnboundedSender<Message>,
28}
29
30impl CurrentContext {
31    pub fn run_with_reactive<T>(new_context: Self, run: impl FnOnce() -> T) -> T {
32        let reactive_context = CURRENT_CONTEXT.with_borrow_mut(|context| {
33            let reactive_context = {
34                let scope_storages = new_context.scopes_storages.borrow();
35                let scope_storage = scope_storages.get(&new_context.scope_id).unwrap();
36                scope_storage.reactive_context.clone()
37            };
38            context.replace(new_context);
39            reactive_context
40        });
41        let res = ReactiveContext::run(reactive_context, run);
42        CURRENT_CONTEXT.with_borrow_mut(|context| context.take());
43        res
44    }
45
46    pub fn run<T>(new_context: Self, run: impl FnOnce() -> T) -> T {
47        CURRENT_CONTEXT.with_borrow_mut(|context| {
48            context.replace(new_context);
49        });
50        let res = run();
51        CURRENT_CONTEXT.with_borrow_mut(|context| context.take());
52        res
53    }
54
55    pub fn with<T>(with: impl FnOnce(&CurrentContext) -> T) -> T {
56        CURRENT_CONTEXT.with(|context| with(context.borrow().as_ref().expect("Your trying to access Freya's current context outside of it, you might be in a separate thread or async task that is not integrated with Freya.")))
57    }
58
59    pub fn try_with<T>(with: impl FnOnce(&CurrentContext) -> T) -> Option<T> {
60        CURRENT_CONTEXT
61            .try_with(|context| {
62                if let Ok(context) = context.try_borrow()
63                    && let Some(context) = context.as_ref()
64                {
65                    Some(with(context))
66                } else {
67                    None
68                }
69            })
70            .ok()
71            .flatten()
72    }
73}
74
75thread_local! {
76    static CURRENT_CONTEXT: RefCell<Option<CurrentContext>> = const { RefCell::new(None) }
77}