use crate::state_access::CloneState;
use crate::state_access::StateAccess;
use crate::store::Store;
use crate::unmount::Unmount;
use std::cell::RefCell;
use std::collections::HashSet;
thread_local! {
static STORE: RefCell<Store> = RefCell::new(Store::new());
}
#[topo::nested]
pub fn use_state<T: 'static, F: FnOnce() -> T>(data_fn: F) -> StateAccess<T> {
use_state_current(data_fn)
}
pub fn use_state_current<T: 'static, F: FnOnce() -> T>(data_fn: F) -> StateAccess<T> {
let current_id = topo::Id::current();
if !state_exists_for_topo_id::<T>(current_id) {
set_state_with_topo_id::<T>(data_fn(), current_id);
}
mark_id_as_active(current_id);
StateAccess::new(current_id)
}
#[topo::nested]
pub fn new_state<T: 'static, F: FnOnce() -> T>(data_fn: F) -> StateAccess<T> {
let count = use_state(|| 0);
count.update(|c| *c += 1);
topo::call_in_slot(count.get(), || use_state_current(data_fn))
}
pub fn set_state_with_topo_id<T: 'static>(data: T, current_id: topo::Id) {
STORE.with(|store_refcell| {
store_refcell
.borrow_mut()
.set_state_with_topo_id::<T>(data, current_id)
})
}
pub fn state_exists_for_topo_id<T: 'static>(id: topo::Id) -> bool {
STORE.with(|store_refcell| store_refcell.borrow().state_exists_with_topo_id::<T>(id))
}
pub fn mark_id_as_active(id: topo::Id) {
STORE.with(|store_refcell| store_refcell.borrow_mut().mark_id_as_active(id))
}
pub fn clone_state_with_topo_id<T: 'static + Clone>(id: topo::Id) -> Option<T> {
STORE.with(|store_refcell| {
store_refcell
.borrow_mut()
.get_state_with_topo_id::<T>(id)
.cloned()
})
}
pub fn remove_state_with_topo_id<T: 'static>(id: topo::Id) -> Option<T> {
STORE.with(|store_refcell| {
store_refcell
.borrow_mut()
.remove_state_with_topo_id::<T>(id)
})
}
pub fn update_state_with_topo_id<T: 'static, F: FnOnce(&mut T) -> ()>(id: topo::Id, func: F) {
let mut item = remove_state_with_topo_id::<T>(id)
.expect("You are trying to update a type state that doesnt exist in this context!");
func(&mut item);
set_state_with_topo_id(item, id);
}
pub fn read_state_with_topo_id<T: 'static, F: FnOnce(&T) -> R, R>(id: topo::Id, func: F) -> R {
let item = remove_state_with_topo_id::<T>(id)
.expect("You are trying to read a type state that doesnt exist in this context!");
let read = func(&item);
set_state_with_topo_id(item, id);
read
}
pub fn purge_and_reset_unseen_ids() {
purge_unseen_ids();
reset_unseen_id_list();
}
pub fn reset_unseen_id_list() {
STORE.with(|store_refcell| {
let mut store_mut = store_refcell.borrow_mut();
store_mut.unseen_ids = HashSet::new();
let ids = store_mut.id_to_key_map.keys().cloned().collect::<Vec<_>>();
for id in ids {
store_mut.unseen_ids.insert(id);
}
})
}
fn purge_unseen_ids() {
STORE.with(|store_refcell| {
let mut store_mut = store_refcell.borrow_mut();
let ids = store_mut.unseen_ids.iter().cloned().collect::<Vec<_>>();
for id in ids {
let key = store_mut.id_to_key_map.remove(&id);
if let Some(key) = key {
store_mut.primary_slotmap.remove(key);
}
}
})
}
pub fn unseen_ids() -> Vec<topo::Id> {
STORE.with(|store_refcell| {
let store_mut = store_refcell.borrow_mut();
store_mut.unseen_ids.iter().cloned().collect::<Vec<_>>()
})
}
pub fn execute_and_remove_unmounts() {
for id in unseen_ids() {
if state_exists_for_topo_id::<Unmount>(id) {
read_state_with_topo_id::<Unmount, _, _>(id, |dt| dt.execute_if_activated());
remove_state_with_topo_id::<Unmount>(id);
}
}
}
#[topo::nested]
pub fn on_unmount<F: Fn() -> () + 'static>(unmount_fn: F) -> StateAccess<Unmount> {
use_state(|| Unmount::new(unmount_fn))
}