diff --git a/packages/stores/src/impls/btreemap.rs b/packages/stores/src/impls/btreemap.rs index 63dda6190..03f41a6dc 100644 --- a/packages/stores/src/impls/btreemap.rs +++ b/packages/stores/src/impls/btreemap.rs @@ -1,3 +1,5 @@ +//! Additional utilities for `BTreeMap` stores. + use std::{borrow::Borrow, collections::BTreeMap, hash::Hash, iter::FusedIterator}; use crate::{store::Store, ReadStore}; diff --git a/packages/stores/src/impls/hashmap.rs b/packages/stores/src/impls/hashmap.rs index 8dfe07835..d2b0478d4 100644 --- a/packages/stores/src/impls/hashmap.rs +++ b/packages/stores/src/impls/hashmap.rs @@ -1,3 +1,5 @@ +//! Additional utilities for `HashMap` stores. + use std::{ borrow::Borrow, collections::HashMap, diff --git a/packages/stores/src/impls/index.rs b/packages/stores/src/impls/index.rs index dca09106f..9330e6f04 100644 --- a/packages/stores/src/impls/index.rs +++ b/packages/stores/src/impls/index.rs @@ -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 { + /// Given a selector and an index, scope the selector to the child at the given index. + fn scope_selector(selector: SelectorScope, index: &Idx) -> SelectorScope; +} + +impl IndexSelector for Vec { + fn scope_selector(selector: SelectorScope, index: &usize) -> SelectorScope { + selector.child_unmapped(*index as _) + } +} + +impl IndexSelector for [T] { + fn scope_selector(selector: SelectorScope, index: &usize) -> SelectorScope { + selector.child_unmapped(*index as _) + } +} + +impl IndexSelector for HashMap +where + I: Hash, +{ + fn scope_selector(selector: SelectorScope, index: &I) -> SelectorScope { + selector.hash_child_unmapped(&index) + } +} + +impl IndexSelector for BTreeMap +where + I: Hash, +{ + fn scope_selector(selector: SelectorScope, index: &I) -> SelectorScope { + selector.hash_child_unmapped(&index) + } +} + impl Store { /// 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 Store { /// ``` pub fn index(self, index: Idx) -> Store> where - T: IndexMut + 'static, - Idx: Hash + 'static, + T: IndexMut + 'static + IndexSelector, Lens: Readable + 'static, { - self.into_selector() - .hash_child_unmapped(&index) + T::scope_selector(self.into_selector(), &index) .map_writer(move |write| IndexWrite { index, write }) .into() } diff --git a/packages/stores/src/impls/mod.rs b/packages/stores/src/impls/mod.rs index 16139dd8e..59f0ccf11 100644 --- a/packages/stores/src/impls/mod.rs +++ b/packages/stores/src/impls/mod.rs @@ -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; diff --git a/packages/stores/src/impls/slice.rs b/packages/stores/src/impls/slice.rs index 9dce2580d..90ba16b21 100644 --- a/packages/stores/src/impls/slice.rs +++ b/packages/stores/src/impls/slice.rs @@ -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>> + where + Lens: Clone, + { + if index >= self.len() { + None + } else { + Some(self.clone().index(index)) + } + } } diff --git a/packages/stores/src/lib.rs b/packages/stores/src/lib.rs index 3d2b8dbf4..31395437d 100644 --- a/packages/stores/src/lib.rs +++ b/packages/stores/src/lib.rs @@ -7,6 +7,7 @@ mod impls; mod store; mod subscriptions; +pub use impls::*; pub use store::*; pub mod scope;