use crate::{
path::{StorePath, StorePathSegment},
ArcStore, KeyMap, Store, StoreFieldTrigger,
};
use or_poisoned::OrPoisoned;
use reactive_graph::{
owner::Storage,
signal::{
guards::{Plain, UntrackedWriteGuard, WriteGuard},
ArcTrigger,
},
traits::{Track, UntrackableGuard},
};
use std::{iter, ops::Deref, sync::Arc};
pub trait StoreField: Sized {
type Value;
type Reader: Deref<Target = Self::Value>;
type Writer: UntrackableGuard<Target = Self::Value>;
#[track_caller]
fn get_trigger(&self, path: StorePath) -> StoreFieldTrigger;
#[track_caller]
fn get_trigger_unkeyed(&self, path: StorePath) -> StoreFieldTrigger;
#[track_caller]
fn path(&self) -> impl IntoIterator<Item = StorePathSegment>;
#[track_caller]
fn path_unkeyed(&self) -> impl IntoIterator<Item = StorePathSegment> {
self.path()
}
#[track_caller]
fn track_field(&self) {
let path = self.path().into_iter().collect();
let trigger = self.get_trigger(path);
trigger.this.track();
trigger.children.track();
}
#[track_caller]
fn reader(&self) -> Option<Self::Reader>;
#[track_caller]
fn writer(&self) -> Option<Self::Writer>;
#[track_caller]
fn keys(&self) -> Option<KeyMap>;
fn triggers_for_current_path(&self) -> Vec<ArcTrigger> {
self.triggers_for_path(self.path().into_iter().collect())
}
fn triggers_for_path(&self, path: StorePath) -> Vec<ArcTrigger> {
let trigger = self.get_trigger(path.clone());
let mut full_path = path;
let mut triggers = Vec::with_capacity(full_path.len() + 2);
triggers.push(trigger.this.clone());
triggers.push(trigger.children.clone());
while !full_path.is_empty() {
full_path.pop();
let inner = self.get_trigger(full_path.clone());
triggers.push(inner.children.clone());
}
triggers.reverse();
triggers
}
fn triggers_for_path_unkeyed(&self, path: StorePath) -> Vec<ArcTrigger> {
let trigger = self.get_trigger_unkeyed(path.clone());
let mut full_path = path;
let mut triggers = Vec::with_capacity(full_path.len() + 2);
triggers.push(trigger.this.clone());
triggers.push(trigger.children.clone());
while !full_path.is_empty() {
full_path.pop();
let inner = self.get_trigger_unkeyed(full_path.clone());
triggers.push(inner.children.clone());
}
triggers.reverse();
triggers
}
}
impl<T> StoreField for ArcStore<T>
where
T: 'static,
{
type Value = T;
type Reader = Plain<T>;
type Writer = WriteGuard<ArcTrigger, UntrackedWriteGuard<T>>;
#[track_caller]
fn get_trigger(&self, path: StorePath) -> StoreFieldTrigger {
let triggers = &self.signals;
let trigger = triggers.write().or_poisoned().get_or_insert(path);
trigger
}
#[track_caller]
fn get_trigger_unkeyed(&self, path: StorePath) -> StoreFieldTrigger {
let caller = std::panic::Location::caller();
let orig_path = path.clone();
let mut path = StorePath::with_capacity(orig_path.len());
for segment in &orig_path {
let parent_is_keyed = self.keys.contains_key(&path);
if parent_is_keyed {
let key = self
.keys
.get_key_for_index(&(path.clone(), segment.0))
.unwrap_or_else(|| {
panic!(
"could not find key for index {:?} at {}",
&(path.clone(), segment.0),
caller
)
});
path.push(key);
} else {
path.push(*segment);
}
}
self.get_trigger(path)
}
#[track_caller]
fn path(&self) -> impl IntoIterator<Item = StorePathSegment> {
iter::empty()
}
#[track_caller]
fn path_unkeyed(&self) -> impl IntoIterator<Item = StorePathSegment> {
iter::empty()
}
#[track_caller]
fn reader(&self) -> Option<Self::Reader> {
Plain::try_new(Arc::clone(&self.value))
}
#[track_caller]
fn writer(&self) -> Option<Self::Writer> {
let trigger = self.get_trigger(Default::default());
let guard = UntrackedWriteGuard::try_new(Arc::clone(&self.value))?;
Some(WriteGuard::new(trigger.children, guard))
}
#[track_caller]
fn keys(&self) -> Option<KeyMap> {
Some(self.keys.clone())
}
}
impl<T, S> StoreField for Store<T, S>
where
T: 'static,
S: Storage<ArcStore<T>>,
{
type Value = T;
type Reader = Plain<T>;
type Writer = WriteGuard<ArcTrigger, UntrackedWriteGuard<T>>;
#[track_caller]
fn get_trigger(&self, path: StorePath) -> StoreFieldTrigger {
self.inner
.try_get_value()
.map(|n| n.get_trigger(path))
.unwrap_or_default()
}
#[track_caller]
fn get_trigger_unkeyed(&self, path: StorePath) -> StoreFieldTrigger {
self.inner
.try_get_value()
.map(|n| n.get_trigger_unkeyed(path))
.unwrap_or_default()
}
#[track_caller]
fn path(&self) -> impl IntoIterator<Item = StorePathSegment> {
self.inner
.try_get_value()
.map(|n| n.path().into_iter().collect::<Vec<_>>())
.unwrap_or_default()
}
#[track_caller]
fn path_unkeyed(&self) -> impl IntoIterator<Item = StorePathSegment> {
self.inner
.try_get_value()
.map(|n| n.path_unkeyed().into_iter().collect::<Vec<_>>())
.unwrap_or_default()
}
#[track_caller]
fn reader(&self) -> Option<Self::Reader> {
self.inner.try_get_value().and_then(|n| n.reader())
}
#[track_caller]
fn writer(&self) -> Option<Self::Writer> {
self.inner.try_get_value().and_then(|n| n.writer())
}
#[track_caller]
fn keys(&self) -> Option<KeyMap> {
self.inner.try_get_value().and_then(|inner| inner.keys())
}
}