use std::any::{Any, TypeId};
use super::runtime::Owner;
use super::with_runtime;
pub fn provide_context<T: 'static>(value: T) {
let registered = with_runtime(|rt| {
let Some(owner_id) = rt.current_owner() else {
return false;
};
let Some(owner) = rt.owners.get_mut(owner_id) else {
return false;
};
owner
.contexts
.insert(TypeId::of::<T>(), std::rc::Rc::new(value));
true
});
if !registered {
super::warn_no_owner("provide_context");
}
}
pub fn use_context<T: 'static + Clone>() -> Option<T> {
with_context::<T, _>(|v| v.clone())
}
pub fn with_context<T: 'static, R>(f: impl FnOnce(&T) -> R) -> Option<R> {
let owner_id = with_runtime(|rt| find_owner_with::<T>(rt, rt.current_owner()))?;
let any_rc: std::rc::Rc<dyn Any> = with_runtime(|rt| {
let owner = rt.owners.get(owner_id)?;
owner.contexts.get(&TypeId::of::<T>()).cloned()
})?;
let typed: &T = any_rc
.downcast_ref::<T>()
.expect("context type tag mismatched stored value");
Some(f(typed))
}
fn find_owner_with<T: 'static>(
rt: &super::runtime::ReactiveRuntime,
start: Option<Owner>,
) -> Option<Owner> {
let type_id = TypeId::of::<T>();
let mut cursor = start;
while let Some(id) = cursor {
let owner = rt.owners.get(id)?;
if owner.contexts.contains_key(&type_id) {
return Some(id);
}
cursor = owner.parent;
}
None
}