use crate::store::Store;
use crate::{DefaultStore, ReactiveMap, ReactiveMapKey, ReactiveMapValue, WritableMode};
use amethystate_core::{MapChange, Signal, SignalSubscription};
use uuid::Uuid;
pub struct MapEntrySignal<K, V, S: Store = DefaultStore> {
key: K,
map: ReactiveMap<K, V, S, WritableMode>,
inner: Signal<V>,
_sync: (SignalSubscription, SignalSubscription),
}
impl<K, V, S: Store> ReactiveMap<K, V, S, WritableMode>
where
K: ReactiveMapKey,
V: ReactiveMapValue,
{
pub fn entry_signal(&self, key: K, default: V) -> MapEntrySignal<K, V, S> {
let initial = self
.get(&key)
.ok()
.flatten()
.unwrap_or_else(|| default.clone());
let inner = Signal::new(initial);
let sync_source = Uuid::new_v4();
let inner_for_read = inner.clone();
let read = self.subscribe_key(key.clone(), move |change| {
let next = match change {
MapChange::Insert { value, .. }
| MapChange::Update {
new_value: value, ..
} => value.clone(),
MapChange::Remove { .. } | MapChange::Clear { .. } => default.clone(),
};
inner_for_read.set(next, Some(sync_source));
});
let map_for_write = self.clone();
let key_for_write = key.clone();
let write = inner.subscribe_with_source(move |value, source| {
if source != Some(sync_source) {
let _ = map_for_write.set_or_create(key_for_write.clone(), value);
}
});
MapEntrySignal {
key,
map: self.clone(),
inner,
_sync: (read, write),
}
}
}
impl<K, V, S> MapEntrySignal<K, V, S>
where
K: ReactiveMapKey,
V: ReactiveMapValue,
S: Store,
{
pub fn signal(&self) -> Signal<V> {
self.inner.clone()
}
pub fn get(&self) -> V {
self.inner.get()
}
pub fn set(&self, value: V) {
self.inner.set(value, None);
}
pub fn key(&self) -> &K {
&self.key
}
pub fn map(&self) -> &ReactiveMap<K, V, S, WritableMode> {
&self.map
}
}