pub struct Store<T: 'static> { /* private fields */ }Expand description
A Copy, process-lifetime handle to one observable value.
Implementations§
Source§impl<T: 'static> Store<T>
impl<T: 'static> Store<T>
Sourcepub fn new(value: T) -> Store<T>
pub fn new(value: T) -> Store<T>
A process-lifetime store, leaked so the handle stays Copy (the property that makes a
Signal pleasant to pass). Create once (a thread_local! + accessor fn is the
idiom); the scoped owner arrives with the persistence container.
pub fn with_untracked<R>(self, f: impl FnOnce(&T) -> R) -> R
Sourcepub fn update(self, label: &'static str, f: impl FnOnce(&mut T))
pub fn update(self, label: &'static str, f: impl FnOnce(&mut T))
Mutate the whole value; announces a store-wide change (every reader wakes).
Sourcepub fn version(self) -> u64
pub fn version(self) -> u64
Bumped on every write; a cheap way for tests to ask “did anything change”.
Source§impl<T: Send + Sync + 'static> Store<T>
impl<T: Send + Sync + 'static> Store<T>
Sourcepub fn transact(self) -> Tx<T>
pub fn transact(self) -> Tx<T>
Open a write transaction: the way a background thread edits. Holding it holds the
store’s write lock, so a reader never sees half of one; dropping it commits and queues
the announcements for Store::pump.
Source§impl<T: Identified + 'static> Store<Keyed<T>>
impl<T: Identified + 'static> Store<Keyed<T>>
Sourcepub fn elem(self, key: impl Into<ModelId<T>>) -> Elem<T>
pub fn elem(self, key: impl Into<ModelId<T>>) -> Elem<T>
One element, addressed by its id: a ModelId, a raw handle from Store::keys,
an integer key, a Uuid, or a string key all convert. O(1), because the collection keeps a
handle→index map.
Sourcepub fn keys(self) -> Vec<u64>
pub fn keys(self) -> Vec<u64>
Tracked read of the collection’s shape (which keys, in what order): what a list widget wants. A field write does not wake it; an insert, a removal or a reorder does.
Sourcepub fn restructure(
self,
label: &'static str,
op: Op,
key: impl Into<ModelId<T>>,
f: impl FnOnce(&mut Keyed<T>),
)where
T: Clone,
pub fn restructure(
self,
label: &'static str,
op: Op,
key: impl Into<ModelId<T>>,
f: impl FnOnce(&mut Keyed<T>),
)where
T: Clone,
Structural change: insert, remove, reorder.
The affected key and the operation are announced alongside the shape path, because a
persistence layer has to choose between an INSERT and a DELETE and cannot infer it from
“the shape changed”, while the UI, which only re-reads keys(), ignores both.
Sourcepub fn push(self, item: T)where
T: Clone,
pub fn push(self, item: T)where
T: Clone,
Append item: the Store::restructure insert, announced under its own key.
Sourcepub fn remove(self, key: impl Into<ModelId<T>>) -> boolwhere
T: Clone,
pub fn remove(self, key: impl Into<ModelId<T>>) -> boolwhere
T: Clone,
Remove the row with key: the Store::restructure delete. Returns false, announcing
nothing, when no such row exists.
Sourcepub fn move_row(self, from: usize, to: usize) -> boolwhere
T: Clone,
pub fn move_row(self, from: usize, to: usize) -> boolwhere
T: Clone,
Move the row at index from to index to, the shape a native list’s reorder gesture
reports. Returns false, announcing nothing, when the move is out of range or in place.
Sourcepub fn next_key(self) -> u64
pub fn next_key(self) -> u64
The next free integer key: one past the largest in use, for a model keyed by a u64
field. Untracked. See Keyed::next_key.
Sourcepub fn merge_row(
self,
key: impl Into<ModelId<T>>,
value: T,
changed: &[&'static str],
) -> boolwhere
T: Clone,
pub fn merge_row(
self,
key: impl Into<ModelId<T>>,
value: T,
changed: &[&'static str],
) -> boolwhere
T: Clone,
Feed one row’s new value from outside the app’s own editing (another connection’s
committed write arriving through a persistence container, an import), replacing the
stored value and announcing each label in changed as that field’s Set. The
announcement is precise: readers of the named fields wake, along with everything
coarser, where a wholesale Store::update wakes only readers of the store itself.
The announcements carry no values (a background transaction’s shape) and the current
author tag; wrap the call in with_author so consumers can tell the merge from the
user’s own edits. Returns false, announcing nothing, when the row is absent: an absent
row is an insert, which is Store::restructure’s job.
Sourcepub fn write_field<V: Clone + 'static>(
self,
key: impl Into<ModelId<T>>,
label: &'static str,
value: V,
) -> boolwhere
T: ApplyField,
pub fn write_field<V: Clone + 'static>(
self,
key: impl Into<ModelId<T>>,
label: &'static str,
value: V,
) -> boolwhere
T: ApplyField,
Write one field by label: front-door semantics (announced at the field’s own path,
prior/new values captured while a consumer wants them, undoable, persisted) without
the generated accessor in scope. The relation machinery writes foreign keys and order
values through this; it is public because any framework-level maintenance faces the
same need. Returns false, announcing nothing, when the row is absent or when
label/V name no field of T (the ApplyField downcast refused).
Sourcepub fn populate(self, rows: Vec<T>)
pub fn populate(self, rows: Vec<T>)
Insert-or-replace rows without announcing: the persistence layer faulting stored rows into its cache. No change record is born (sinks, undo and autosave all stay quiet: the rows are the database’s own contents arriving, not edits), and no trigger wakes: a faulting read populates before anything binds, so there is nobody to wake yet. The version still bumps, so version-watching tests see the population.
Sourcepub fn depopulate(self, key: impl Into<ModelId<T>>) -> bool
pub fn depopulate(self, key: impl Into<ModelId<T>>) -> bool
Remove one row without announcing: the persistence layer evicting a clean cached row.
The row is not deleted anywhere; it stops being resident, and a later fault
brings it back. Callers guard with Store::is_observed: evicting a row something is
bound to would flip that binding to its Default with no wakeup to correct it.
Sourcepub fn depopulate_many(self, keys: &[u64]) -> usize
pub fn depopulate_many(self, keys: &[u64]) -> usize
Store::depopulate, batched: One retain and one reindex for the whole set, where
per-key removal would rebuild the key map per row, the difference between an eviction
pass costing O(cache) and O(cache × evicted). Returns how many rows left.
Sourcepub fn is_observed(self, key: impl Into<ModelId<T>>) -> bool
pub fn is_observed(self, key: impl Into<ModelId<T>>) -> bool
Whether anything currently observes this element: a trigger on the element’s own path, or on any path under it (a bound field, a nested struct). The eviction guard: a row nobody observes can leave the cache silently, because the next reader faults it back.
Trait Implementations§
impl<T> Copy for Store<T>
impl<T: Send + Sync> Send for Store<T>
Source§impl<T: 'static> Source<T> for Store<T>
impl<T: 'static> Source<T> for Store<T>
Source§fn path(self) -> Path
fn path(self) -> Path
Source§fn node(self) -> NodeId
fn node(self) -> NodeId
Source§fn components(self, out: &mut Vec<u64>)
fn components(self, out: &mut Vec<u64>)
fn with_value_untracked<R>(self, f: impl FnOnce(Option<&T>) -> R) -> R
Source§fn update_value(self, f: impl FnOnce(&mut T)) -> bool
fn update_value(self, f: impl FnOnce(&mut T)) -> bool
fn bump_version(self)
Source§const DYNAMIC: bool = false
const DYNAMIC: bool = false
Source::track_extra.