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_root_context<T: Clone + 'static>() -> Option<T> {
35 try_consume_context_from_scope_id(Some(ScopeId::ROOT))
36}
37
38pub fn consume_context<T: Clone + 'static>() -> T {
39 try_consume_context_from_scope_id(None)
40 .unwrap_or_else(|| panic!("Context <{}> was not found.", std::any::type_name::<T>()))
41}
42
43pub fn consume_root_context<T: Clone + 'static>() -> T {
44 try_consume_context_from_scope_id(Some(ScopeId::ROOT)).unwrap_or_else(|| {
45 panic!(
46 "Root context <{}> was not found.",
47 std::any::type_name::<T>()
48 )
49 })
50}
51
52pub fn try_consume_context_from_scope_id<T: Clone + 'static>(
53 scope_id: Option<ScopeId>,
54) -> Option<T> {
55 CurrentContext::with(|context| {
56 let scopes_storages = context.scopes_storages.borrow_mut();
57
58 let mut ladder = vec![scope_id.unwrap_or(context.scope_id)];
59
60 let type_id = TypeId::of::<T>();
61
62 while let Some(scope_id) = ladder.pop() {
63 let scopes_storage = scopes_storages.get(&scope_id)?;
64
65 if let Some(context) = scopes_storage.contexts.get(&type_id) {
66 return context.downcast_ref::<T>().cloned();
67 } else if let Some(parent_scope_id) = scopes_storage.parent_id {
68 ladder.push(parent_scope_id);
69 }
70 }
71
72 None
73 })
74}
75
76pub fn use_provide_context<T: Clone + 'static>(init: impl FnOnce() -> T) -> T {
77 use_hook(|| {
78 let ctx = init();
79 provide_context(ctx.clone());
80 ctx
81 })
82}
83
84pub fn use_consume<T: Clone + 'static>() -> T {
85 use_hook(|| consume_context())
86}
87
88pub fn use_try_consume<T: Clone + 'static>() -> Option<T> {
89 use_hook(|| try_consume_context())
90}