Struct StateStore

Source
pub struct StateStore { /* private fields */ }
Expand description

Type-erased retained signal storage keyed by tree, element, and slot index.

The store has no automatic capacity limit; reconciliation must remove unmounted element/tree slots. Stored values and returned signals are Rc<RefCell<_>> based, making this a single-UI-thread facility. The first concrete type used for a mounted key remains mandatory until removal.

§Examples

use ailloli_ui_runtime::app::StateStore;
let _store = StateStore::default();

Implementations§

Source§

impl StateStore

Provides the operations defined for StateStore.

Source

pub fn signal<T: 'static>( &mut self, element_id: ElementId, slot_index: usize, initial: T, invalidate: Rc<dyn Fn()>, ) -> Signal<T>

Returns a signal stored in the legacy root-tree namespace (tree 0).

Retained runtimes use Self::signal_scoped so equal ElementId values from independent element trees cannot alias one another.

initial is evaluated by the caller before this method; it is discarded if the slot already exists. Returned handles share value/source and keep the invalidator installed when the slot was first created.

§Panics

Panics if this mounted tree-0/element/index key was first created with a different concrete T.

§Examples
use std::rc::Rc;
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::StateStore;
let mut store = StateStore::default();
let first = store.signal(ElementId(1), 0, 10, Rc::new(|| {}));
first.set(11);
let reused = store.signal(ElementId(1), 0, 99, Rc::new(|| {}));
assert_eq!((reused.read(), reused.revision()), (11, 1));
Source

pub fn signal_scoped<T: 'static>( &mut self, element_tree_id: ElementTreeId, element_id: ElementId, slot_index: usize, initial: T, invalidate: Rc<dyn Fn()>, ) -> Signal<T>

Returns a signal isolated to one retained element tree.

Equal element IDs and slot indices in different element_tree_id namespaces do not alias. As with Self::signal, initial is eagerly constructed before the method sees whether the slot exists.

§Panics

Panics when the existing scoped key contains a different concrete type.

§Examples
use std::rc::Rc;
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::{app::StateStore, popup::ElementTreeId};
let mut store = StateStore::default();
let a = store.signal_scoped(ElementTreeId::new(1), ElementId(1), 0, 10, Rc::new(|| {}));
let b = store.signal_scoped(ElementTreeId::new(2), ElementId(1), 0, 20, Rc::new(|| {}));
a.set(11);
assert_eq!((a.read(), b.read()), (11, 20));
Source

pub fn signal_scoped_with<T: 'static>( &mut self, element_tree_id: ElementTreeId, element_id: ElementId, slot_index: usize, initial: impl FnOnce() -> T, invalidate: Rc<dyn Fn()>, ) -> Signal<T>

Lazily initializes a retained signal slot. The factory is never evaluated again while the same typed slot remains mounted.

Every returned handle shares the slot value, source revision, first historical invalidator, and dynamic retained subscribers. The store retains its Rcs until removal; outstanding handles keep old state alive after removal, while a later lookup creates a fresh independent slot.

§Panics

Panics when an existing scoped key contains a different concrete T. A panic from initial propagates and leaves the entry vacant.

§Examples
use std::{cell::Cell, rc::Rc};
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::{app::StateStore, popup::ElementTreeId};
let mut store = StateStore::default();
let calls = Rc::new(Cell::new(0));
let counted = calls.clone();
let first = store.signal_scoped_with(ElementTreeId::new(1), ElementId(1), 0, move || { counted.set(counted.get() + 1); 7 }, Rc::new(|| {}));
let second = store.signal_scoped_with(ElementTreeId::new(1), ElementId(1), 0, || 99, Rc::new(|| {}));
assert_eq!((first.read(), second.read(), calls.get()), (7, 7, 1));
Source

pub fn remove_element(&mut self, element_id: ElementId)

Removes an element from the legacy root-tree namespace (tree 0).

Every slot index and concrete type for the element is removed. Missing elements are a no-op. Existing Signal handles continue to own and mutate their detached values; the next lookup creates fresh state.

§Examples
use std::rc::Rc;
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::app::StateStore;
let mut store = StateStore::default();
let old = store.signal(ElementId(1), 0, 4, Rc::new(|| {}));
store.remove_element(ElementId(1));
let fresh = store.signal(ElementId(1), 0, 9, Rc::new(|| {}));
assert_eq!((old.read(), fresh.read()), (4, 9));
Source

pub fn remove_element_scoped( &mut self, element_tree_id: ElementTreeId, element_id: ElementId, )

Removes all state slots belonging to element_id in one tree only.

This scans the full sparse store in O(total slots). Other trees (even with the same element ID) remain intact.

§Examples
use std::rc::Rc;
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::{app::StateStore, popup::ElementTreeId};
let mut store = StateStore::default();
let other = store.signal_scoped(ElementTreeId::new(2), ElementId(1), 0, 20, Rc::new(|| {}));
let _ = store.signal_scoped(ElementTreeId::new(1), ElementId(1), 0, 10, Rc::new(|| {}));
store.remove_element_scoped(ElementTreeId::new(1), ElementId(1));
assert_eq!(other.read(), 20);

Trait Implementations§

Source§

impl Default for StateStore

Source§

fn default() -> StateStore

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> ErasedDestructor for T
where T: 'static,