freya_core/lifecycle/
context.rs1use std::{
2 any::TypeId,
3 rc::Rc,
4};
5
6use crate::{
7 current_context::CurrentContext,
8 prelude::use_hook,
9 scope_id::ScopeId,
10};
11
12pub fn provide_context<T: Clone + 'static>(value: T) {
13 provide_context_for_scope_id(value, None)
14}
15
16pub fn provide_context_for_scope_id<T: Clone + 'static>(
17 value: T,
18 scope_id: impl Into<Option<ScopeId>>,
19) {
20 CurrentContext::with(|context| {
21 let mut scopes_storages = context.scopes_storages.borrow_mut();
22 let scopes_storage = scopes_storages
23 .get_mut(&scope_id.into().unwrap_or(context.scope_id))
24 .unwrap();
25 let type_id = TypeId::of::<T>();
26 scopes_storage.contexts.insert(type_id, Rc::new(value));
27 })
28}
29
30pub fn try_consume_context<T: Clone + 'static>() -> Option<T> {
31 try_consume_context_from_scope_id(None)
32}
33
34pub fn try_consume_own_context<T: Clone + 'static>() -> Option<T> {
36 CurrentContext::with(|context| {
37 let scopes_storages = context.scopes_storages.borrow();
38 let scopes_storage = scopes_storages.get(&context.scope_id)?;
39 let type_id = TypeId::of::<T>();
40 scopes_storage
41 .contexts
42 .get(&type_id)?
43 .downcast_ref::<T>()
44 .cloned()
45 })
46}
47
48pub fn try_consume_root_context<T: Clone + 'static>() -> Option<T> {
49 try_consume_context_from_scope_id(Some(ScopeId::ROOT))
50}
51
52pub fn consume_context<T: Clone + 'static>() -> T {
53 try_consume_context_from_scope_id(None)
54 .unwrap_or_else(|| panic!("Context <{}> was not found.", std::any::type_name::<T>()))
55}
56
57pub fn consume_root_context<T: Clone + 'static>() -> T {
58 try_consume_context_from_scope_id(Some(ScopeId::ROOT)).unwrap_or_else(|| {
59 panic!(
60 "Root context <{}> was not found.",
61 std::any::type_name::<T>()
62 )
63 })
64}
65
66pub fn try_consume_context_from_scope_id<T: Clone + 'static>(
67 scope_id: Option<ScopeId>,
68) -> Option<T> {
69 CurrentContext::with(|context| {
70 let scopes_storages = context.scopes_storages.borrow_mut();
71
72 let mut ladder = vec![scope_id.unwrap_or(context.scope_id)];
73
74 let type_id = TypeId::of::<T>();
75
76 while let Some(scope_id) = ladder.pop() {
77 let scopes_storage = scopes_storages.get(&scope_id)?;
78
79 if let Some(context) = scopes_storage.contexts.get(&type_id) {
80 return context.downcast_ref::<T>().cloned();
81 } else if let Some(parent_scope_id) = scopes_storage.parent_id {
82 ladder.push(parent_scope_id);
83 }
84 }
85
86 None
87 })
88}
89
90pub fn use_provide_context<T: Clone + 'static>(init: impl FnOnce() -> T) -> T {
93 use_hook(|| {
94 let ctx = init();
95 provide_context(ctx.clone());
96 ctx
97 })
98}
99
100pub fn use_consume<T: Clone + 'static>() -> T {
102 use_hook(|| consume_context())
103}
104
105pub fn use_try_consume<T: Clone + 'static>() -> Option<T> {
107 use_hook(|| try_consume_context())
108}