use std::{collections::HashMap, ops::{Deref, DerefMut}, sync::{Arc, RwLock}}; use leptos::prelude::*; use tracing::debug; // TODO: get rid of this // V has to be an arc signal #[derive(Debug)] pub struct ArcStateStore { store: Arc, usize)>>>, } impl PartialEq for ArcStateStore { fn eq(&self, other: &Self) -> bool { Arc::ptr_eq(&self.store, &other.store) } } impl Clone for ArcStateStore { fn clone(&self) -> Self { Self { store: Arc::clone(&self.store), } } } impl Eq for ArcStateStore {} impl ArcStateStore { pub fn new() -> Self { Self { store: Arc::new(RwLock::new(HashMap::new())), } } } #[derive(Debug)] pub struct StateStore { inner: ArenaItem, S>, } impl Dispose for StateStore { fn dispose(self) { self.inner.dispose() } } impl StateStore where K: Send + Sync + 'static, V: Send + Sync + 'static, { pub fn new() -> Self { Self::new_with_storage() } } impl StateStore where K: 'static, V: 'static, S: Storage>, { pub fn new_with_storage() -> Self { Self { inner: ArenaItem::new_with_storage(ArcStateStore::new()), } } } impl StateStore where K: 'static, V: 'static, { pub fn new_local() -> Self { Self::new_with_storage() } } impl< K: std::marker::Send + std::marker::Sync + 'static, V: std::marker::Send + std::marker::Sync + 'static, > From> for StateStore { fn from(value: ArcStateStore) -> Self { Self { inner: ArenaItem::new_with_storage(value), } } } impl FromLocal> for StateStore { fn from_local(value: ArcStateStore) -> Self { Self { inner: ArenaItem::new_with_storage(value), } } } impl Copy for StateStore {} impl Clone for StateStore { fn clone(&self) -> Self { *self } } impl StateStore where K: Send + Sync + 'static, V: Send + Sync + 'static, { pub fn store(&self, key: K, value: V) -> StateListener { { let store = self.inner.try_get_value().unwrap(); let mut store = store.store.write().unwrap(); debug!("store state: {:?}", store); if let Some((v, count)) = store.get_mut(&key) { debug!("updating old value already in store"); v.set(value); *count += 1; StateListener { value: v.clone(), cleaner: StateCleaner { key, state_store: self.clone(), }, } } else { let v = ArcRwSignal::new(value); store.insert(key.clone(), (v.clone(), 1)); debug!("inserting new value: {:?}", store); StateListener { value: v.into(), cleaner: StateCleaner { key, state_store: self.clone(), }, } } } } } impl StateStore where K: Eq + std::hash::Hash + Send + Sync + 'static, V: Send + Sync + 'static, { pub fn update(&self, key: &K, value: V) { let store = self.inner.try_get_value().unwrap(); let mut store = store.store.write().unwrap(); if let Some((v, _)) = store.get_mut(key) { v.set(value) } } pub fn modify(&self, key: &K, modify: impl Fn(&mut V)) { let store = self.inner.try_get_value().unwrap(); let mut store = store.store.write().unwrap(); if let Some((v, _)) = store.get_mut(key) { v.update(|v| modify(v)); } } fn remove(&self, key: &K) { // let store = self.inner.try_get_value().unwrap(); // let mut store = store.store.write().unwrap(); // if let Some((_v, count)) = store.get_mut(key) { // *count -= 1; // if *count == 0 { // store.remove(key); // debug!("dropped item from store"); // } // } } } #[derive(Clone)] pub struct StateListener where K: Eq + std::hash::Hash + 'static + std::marker::Send + std::marker::Sync, V: 'static + std::marker::Send + std::marker::Sync, { value: ArcRwSignal, cleaner: StateCleaner, } impl< K: std::cmp::Eq + std::hash::Hash + std::marker::Send + std::marker::Sync, V: std::marker::Send + std::marker::Sync, > Deref for StateListener { type Target = ArcRwSignal; fn deref(&self) -> &Self::Target { &self.value } } impl DerefMut for StateListener { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.value } } struct ArcStateCleaner { key: K, state_store: ArcStateStore, } struct StateCleaner where K: Eq + std::hash::Hash + Send + Sync + 'static, V: Send + Sync + 'static, { key: K, state_store: StateStore, } impl Clone for StateCleaner where K: Eq + std::hash::Hash + Clone + Send + Sync, V: Send + Sync, { fn clone(&self) -> Self { { let store = self.state_store.inner.try_get_value().unwrap(); let mut store = store.store.write().unwrap(); if let Some((_v, count)) = store.get_mut(&self.key) { *count += 1; } } Self { key: self.key.clone(), state_store: self.state_store.clone(), } } } impl Drop for StateCleaner { fn drop(&mut self) { self.state_store.remove(&self.key); } }