freya_core/
current_context.rs1use 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
20pub 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 = {
33 let scope_storages = new_context.scopes_storages.borrow();
34 let scope_storage = scope_storages.get(&new_context.scope_id).unwrap();
35 scope_storage.reactive_context.clone()
36 };
37 Self::run(new_context, || ReactiveContext::run(reactive_context, run))
38 }
39
40 pub fn run<T>(new_context: Self, run: impl FnOnce() -> T) -> T {
41 let previous = CURRENT_CONTEXT.with_borrow_mut(|context| context.replace(new_context));
42 let result = run();
43 let _removed_context =
44 CURRENT_CONTEXT.with_borrow_mut(|context| std::mem::replace(context, previous));
45 result
46 }
47
48 pub(crate) fn run_in_scope<T>(scope_id: ScopeId, run: impl FnOnce() -> T) -> T {
52 let previous_scope_id = CURRENT_CONTEXT.with_borrow_mut(|context| {
53 context
54 .as_mut()
55 .map(|context| std::mem::replace(&mut context.scope_id, scope_id))
56 });
57
58 let res = run();
59
60 CURRENT_CONTEXT.with_borrow_mut(|context| {
61 if let Some(context) = context.as_mut()
62 && let Some(previous_scope_id) = previous_scope_id
63 {
64 context.scope_id = previous_scope_id;
65 }
66 });
67
68 res
69 }
70
71 pub fn with<T>(with: impl FnOnce(&CurrentContext) -> T) -> T {
72 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.")))
73 }
74
75 pub fn try_with<T>(with: impl FnOnce(&CurrentContext) -> T) -> Option<T> {
76 CURRENT_CONTEXT
77 .try_with(|context| {
78 if let Ok(context) = context.try_borrow()
79 && let Some(context) = context.as_ref()
80 {
81 Some(with(context))
82 } else {
83 None
84 }
85 })
86 .ok()
87 .flatten()
88 }
89}
90
91thread_local! {
92 static CURRENT_CONTEXT: RefCell<Option<CurrentContext>> = const { RefCell::new(None) }
93}