use std::{any::Any, cell::RefCell, collections::HashMap, rc::Rc, sync::Arc}; use dioxus_core::ScopeId; use im_rc::HashSet; use crate::Readable; pub type AtomId = *const (); pub struct AtomRoot { pub atoms: RefCell>, pub update_any: Arc, } pub struct Slot { pub value: Rc, pub subscribers: HashSet, } impl AtomRoot { pub fn new(update_any: Arc) -> Self { Self { update_any, atoms: RefCell::new(HashMap::new()), } } pub fn initialize(&self, f: impl Readable) { let id = f.unique_id(); if self.atoms.borrow().get(&id).is_none() { self.atoms.borrow_mut().insert( id, Slot { value: Rc::new(f.init()), subscribers: HashSet::new(), }, ); } } pub fn register(&self, f: impl Readable, scope: ScopeId) -> Rc { let mut atoms = self.atoms.borrow_mut(); // initialize the value if it's not already initialized if let Some(slot) = atoms.get_mut(&f.unique_id()) { slot.subscribers.insert(scope); slot.value.clone().downcast().unwrap() } else { let value = Rc::new(f.init()); let mut subscribers = HashSet::new(); subscribers.insert(scope); atoms.insert( f.unique_id(), Slot { value: value.clone(), subscribers, }, ); value } } pub fn set(&self, ptr: AtomId, value: V) { let mut atoms = self.atoms.borrow_mut(); if let Some(slot) = atoms.get_mut(&ptr) { slot.value = Rc::new(value); log::trace!("found item with subscribers {:?}", slot.subscribers); for scope in &slot.subscribers { log::trace!("updating subcsriber"); (self.update_any)(*scope); } } else { log::trace!("no atoms found for {:?}", ptr); atoms.insert( ptr, Slot { value: Rc::new(value), subscribers: HashSet::new(), }, ); } } pub fn unsubscribe(&self, ptr: AtomId, scope: ScopeId) { let mut atoms = self.atoms.borrow_mut(); if let Some(slot) = atoms.get_mut(&ptr) { slot.subscribers.remove(&scope); } } // force update of all subscribers pub fn force_update(&self, ptr: AtomId) { if let Some(slot) = self.atoms.borrow_mut().get(&ptr) { for scope in slot.subscribers.iter() { log::trace!("updating subcsriber"); (self.update_any)(*scope); } } } pub fn read(&self, f: impl Readable) -> Rc { let mut atoms = self.atoms.borrow_mut(); // initialize the value if it's not already initialized if let Some(slot) = atoms.get_mut(&f.unique_id()) { slot.value.clone().downcast().unwrap() } else { let value = Rc::new(f.init()); atoms.insert( f.unique_id(), Slot { value: value.clone(), subscribers: HashSet::new(), }, ); value } } }