use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::collections::HashMap;
#[cfg(test)]
mod tests;
use crate::hook_context::with_hook_context;
thread_local! {
static CONTEXT_PROVIDERS: RefCell<HashMap<TypeId, Vec<Box<dyn Any + Send + Sync>>>> =
RefCell::new(HashMap::new());
}
pub fn clear_context_providers() {
CONTEXT_PROVIDERS.with(|providers| {
providers.borrow_mut().clear();
});
}
pub fn use_context_provider<T, F>(create_value: F) -> T
where
T: Clone + Send + Sync + 'static,
F: FnOnce() -> T,
{
with_hook_context(|_ctx| {
let type_id = TypeId::of::<T>();
let value = create_value();
let value_clone = value.clone();
CONTEXT_PROVIDERS.with(|providers| {
let mut providers = providers.borrow_mut();
let provider_stack = providers.entry(type_id).or_default();
provider_stack.push(Box::new(value_clone));
});
value
})
}
pub fn use_context<T>() -> T
where
T: Clone + Send + Sync + 'static,
{
with_hook_context(|_ctx| {
let type_id = TypeId::of::<T>();
let value = CONTEXT_PROVIDERS.with(|providers| {
let providers = providers.borrow();
if let Some(provider_stack) = providers.get(&type_id)
&& let Some(last_provider) = provider_stack.last()
&& let Some(value) = last_provider.downcast_ref::<T>()
{
return Some(value.clone());
}
None
});
if let Some(value) = value {
return value;
}
panic!(
"Context value for type {} not found. Make sure to call use_context_provider in a parent component.",
std::any::type_name::<T>()
);
})
}