Fix stores with vec index method and expose opaque writer types (#4684)

* Use a different indexing method for each data structure

* add a get method for slices

* Rename trait for clarity and simplicity

---------

Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
This commit is contained in:
Evan AlmloffandJonathan Kelley authored and GitHub committed 2025-10-03 18:43:54 -07:00
1 parent 8d26a5d22e
commit ecec70f5e8
6 files changed
+74 -8

No files matched your search

+2
View File
@@ -1,3 +1,5 @@
//! Additional utilities for `BTreeMap` stores.
use std::{borrow::Borrow, collections::BTreeMap, hash::Hash, iter::FusedIterator};
use crate::{store::Store, ReadStore};
+2
View File
@@ -1,3 +1,5 @@
//! Additional utilities for `HashMap` stores.
use std::{
borrow::Borrow,
collections::HashMap,
+43 -5
View File
@@ -1,14 +1,54 @@
//! Additional utilities for indexing into stores.
use std::{
collections::{BTreeMap, HashMap},
hash::Hash,
ops::{self, Index, IndexMut},
};
use crate::{store::Store, ReadStore};
use crate::{scope::SelectorScope, store::Store, ReadStore};
use dioxus_signals::{
AnyStorage, BorrowError, BorrowMutError, ReadSignal, Readable, UnsyncStorage, Writable,
WriteLock, WriteSignal,
};
/// The way a data structure index into its children based on a key. The selector must use this indexing
/// method consistently to ensure that the same key always maps to the same child.
pub trait IndexSelector<Idx> {
/// Given a selector and an index, scope the selector to the child at the given index.
fn scope_selector<Lens>(selector: SelectorScope<Lens>, index: &Idx) -> SelectorScope<Lens>;
}
impl<T> IndexSelector<usize> for Vec<T> {
fn scope_selector<Lens>(selector: SelectorScope<Lens>, index: &usize) -> SelectorScope<Lens> {
selector.child_unmapped(*index as _)
}
}
impl<T> IndexSelector<usize> for [T] {
fn scope_selector<Lens>(selector: SelectorScope<Lens>, index: &usize) -> SelectorScope<Lens> {
selector.child_unmapped(*index as _)
}
}
impl<K, V, I> IndexSelector<I> for HashMap<K, V>
where
I: Hash,
{
fn scope_selector<Lens>(selector: SelectorScope<Lens>, index: &I) -> SelectorScope<Lens> {
selector.hash_child_unmapped(&index)
}
}
impl<K, V, I> IndexSelector<I> for BTreeMap<K, V>
where
I: Hash,
{
fn scope_selector<Lens>(selector: SelectorScope<Lens>, index: &I) -> SelectorScope<Lens> {
selector.hash_child_unmapped(&index)
}
}
impl<Lens, T> Store<T, Lens> {
/// Index into the store, returning a store that allows access to the item at the given index. The
/// new store will only update when the item at the index changes.
@@ -23,12 +63,10 @@ impl<Lens, T> Store<T, Lens> {
/// ```
pub fn index<Idx>(self, index: Idx) -> Store<T::Output, IndexWrite<Idx, Lens>>
where
T: IndexMut<Idx> + 'static,
Idx: Hash + 'static,
T: IndexMut<Idx> + 'static + IndexSelector<Idx>,
Lens: Readable<Target = T> + 'static,
{
self.into_selector()
.hash_child_unmapped(&index)
T::scope_selector(self.into_selector(), &index)
.map_writer(move |write| IndexWrite { index, write })
.into()
}
+3 -3
View File
@@ -1,7 +1,7 @@
mod btreemap;
pub mod btreemap;
mod deref;
mod hashmap;
mod index;
pub mod hashmap;
pub mod index;
mod option;
mod result;
mod slice;
+23
View File
@@ -57,4 +57,27 @@ where
{
(0..self.len()).map(move |i| self.clone().index(i))
}
/// Try to get an item from slice. This will only track the shallow state of the slice.
/// It will only cause a re-run if the length of the slice could change. The new store
/// will only update when the item at the index changes.
///
/// # Example
/// ```rust, no_run
/// use dioxus_stores::*;
/// let store = use_store(|| vec![1, 2, 3]);
/// let indexed_store = store.get(1).unwrap();
/// // The indexed store can access the store methods of the indexed store.
/// assert_eq!(indexed_store(), 2);
/// ```
pub fn get(&self, index: usize) -> Option<Store<I, IndexWrite<usize, Lens>>>
where
Lens: Clone,
{
if index >= self.len() {
None
} else {
Some(self.clone().index(index))
}
}
}
+1
View File
@@ -7,6 +7,7 @@
mod impls;
mod store;
mod subscriptions;
pub use impls::*;
pub use store::*;
pub mod scope;