dioxus_stores/impls/
btreemap.rs

1//! Additional utilities for `BTreeMap` stores.
2
3use std::{borrow::Borrow, collections::BTreeMap, hash::Hash, iter::FusedIterator};
4
5use crate::{store::Store, ReadStore};
6use dioxus_signals::{
7    AnyStorage, BorrowError, BorrowMutError, ReadSignal, Readable, ReadableExt, UnsyncStorage,
8    Writable, WriteLock, WriteSignal,
9};
10
11impl<Lens: Readable<Target = BTreeMap<K, V>> + 'static, K: 'static, V: 'static>
12    Store<BTreeMap<K, V>, Lens>
13{
14    /// Get the length of the BTreeMap. This method will track the store shallowly and only cause
15    /// re-runs when items are added or removed from the map, not when existing values are modified.
16    ///
17    /// # Example
18    /// ```rust, no_run
19    /// use dioxus_stores::*;
20    /// use dioxus::prelude::*;
21    /// use std::collections::BTreeMap;
22    /// let mut store = use_store(|| BTreeMap::new());
23    /// assert_eq!(store.len(), 0);
24    /// store.insert(0, "value".to_string());
25    /// assert_eq!(store.len(), 1);
26    /// ```
27    pub fn len(&self) -> usize {
28        self.selector().track_shallow();
29        self.selector().peek().len()
30    }
31
32    /// Check if the BTreeMap is empty. This method will track the store shallowly and only cause
33    /// re-runs when items are added or removed from the map, not when existing values are modified.
34    ///
35    /// # Example
36    /// ```rust, no_run
37    /// use dioxus_stores::*;
38    /// use dioxus::prelude::*;
39    /// use std::collections::BTreeMap;
40    /// let mut store = use_store(|| BTreeMap::new());
41    /// assert!(store.is_empty());
42    /// store.insert(0, "value".to_string());
43    /// assert!(!store.is_empty());
44    /// ```
45    pub fn is_empty(&self) -> bool {
46        self.selector().track_shallow();
47        self.selector().peek().is_empty()
48    }
49
50    /// Iterate over the current entries in the BTreeMap, returning a tuple of the key and a store for the value. This method
51    /// will track the store shallowly and only cause re-runs when items are added or removed from the map, not when existing
52    /// values are modified.
53    ///
54    /// # Example
55    ///
56    /// ```rust, no_run
57    /// use dioxus_stores::*;
58    /// use dioxus::prelude::*;
59    /// use std::collections::BTreeMap;
60    /// let mut store = use_store(|| BTreeMap::new());
61    /// store.insert(0, "value1".to_string());
62    /// store.insert(1, "value2".to_string());
63    /// for (key, value_store) in store.iter() {
64    ///     println!("{}: {}", key, value_store.read());
65    /// }
66    /// ```
67    pub fn iter(
68        &self,
69    ) -> impl ExactSizeIterator<Item = (K, Store<V, GetWrite<K, Lens>>)>
70           + DoubleEndedIterator
71           + FusedIterator
72           + '_
73    where
74        K: Hash + Ord + Clone,
75        Lens: Clone,
76    {
77        self.selector().track_shallow();
78        let keys: Vec<_> = self.selector().peek_unchecked().keys().cloned().collect();
79        keys.into_iter().map(move |key| {
80            let value = self.clone().get(key.clone()).unwrap();
81            (key, value)
82        })
83    }
84
85    /// Get an iterator over the values in the BTreeMap. This method will track the store shallowly and only cause
86    /// re-runs when items are added or removed from the map, not when existing values are modified.
87    ///
88    /// # Example
89    /// ```rust, no_run
90    /// use dioxus_stores::*;
91    /// use dioxus::prelude::*;
92    /// use std::collections::BTreeMap;
93    /// let mut store = use_store(|| BTreeMap::new());
94    /// store.insert(0, "value1".to_string());
95    /// store.insert(1, "value2".to_string());
96    /// for value_store in store.values() {
97    ///     println!("{}", value_store.read());
98    /// }
99    /// ```
100    pub fn values(
101        &self,
102    ) -> impl ExactSizeIterator<Item = Store<V, GetWrite<K, Lens>>>
103           + DoubleEndedIterator
104           + FusedIterator
105           + '_
106    where
107        K: Hash + Ord + Clone,
108        Lens: Clone,
109    {
110        self.selector().track_shallow();
111        let keys = self.selector().peek().keys().cloned().collect::<Vec<_>>();
112        keys.into_iter()
113            .map(move |key| self.clone().get(key).unwrap())
114    }
115
116    /// Insert a new key-value pair into the BTreeMap. This method will mark the store as shallowly dirty, causing
117    /// re-runs of any reactive scopes that depend on the shape of the map.
118    ///
119    /// # Example
120    /// ```rust, no_run
121    /// use dioxus_stores::*;
122    /// use dioxus::prelude::*;
123    /// use std::collections::BTreeMap;
124    /// let mut store = use_store(|| BTreeMap::new());
125    /// assert!(store.get(0).is_none());
126    /// store.insert(0, "value".to_string());
127    /// assert_eq!(store.get(0).unwrap().cloned(), "value".to_string());
128    /// ```
129    pub fn insert(&mut self, key: K, value: V)
130    where
131        K: Ord,
132        Lens: Writable,
133    {
134        self.selector().mark_dirty_shallow();
135        self.selector().write_untracked().insert(key, value);
136    }
137
138    /// Remove a key-value pair from the BTreeMap. This method will mark the store as shallowly dirty, causing
139    /// re-runs of any reactive scopes that depend on the shape of the map or the value of the removed key.
140    ///
141    /// # Example
142    /// ```rust, no_run
143    /// use dioxus_stores::*;
144    /// use dioxus::prelude::*;
145    /// use std::collections::BTreeMap;
146    /// let mut store = use_store(|| BTreeMap::new());
147    /// store.insert(0, "value".to_string());
148    /// assert_eq!(store.get(0).unwrap().cloned(), "value".to_string());
149    /// let removed_value = store.remove(&0);
150    /// assert_eq!(removed_value, Some("value".to_string()));
151    /// assert!(store.get(0).is_none());
152    /// ```
153    pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
154    where
155        Q: ?Sized + Ord + 'static,
156        K: Borrow<Q> + Ord,
157        Lens: Writable,
158    {
159        self.selector().mark_dirty_shallow();
160        self.selector().write_untracked().remove(key)
161    }
162
163    /// Clear the BTreeMap, removing all key-value pairs. This method will mark the store as shallowly dirty,
164    /// causing re-runs of any reactive scopes that depend on the shape of the map.
165    ///
166    /// # Example
167    /// ```rust, no_run
168    /// use dioxus_stores::*;
169    /// use dioxus::prelude::*;
170    /// use std::collections::BTreeMap;
171    /// let mut store = use_store(|| BTreeMap::new());
172    /// store.insert(1, "value1".to_string());
173    /// store.insert(2, "value2".to_string());
174    /// assert_eq!(store.len(), 2);
175    /// store.clear();
176    /// assert!(store.is_empty());
177    /// ```
178    pub fn clear(&mut self)
179    where
180        Lens: Writable,
181    {
182        self.selector().mark_dirty_shallow();
183        self.selector().write_untracked().clear();
184    }
185
186    /// Retain only the key-value pairs that satisfy the given predicate. This method will mark the store as shallowly dirty,
187    /// causing re-runs of any reactive scopes that depend on the shape of the map or the values retained.
188    ///
189    /// # Example
190    /// ```rust, no_run
191    /// use dioxus_stores::*;
192    /// use dioxus::prelude::*;
193    /// use std::collections::BTreeMap;
194    /// let mut store = use_store(|| BTreeMap::new());
195    /// store.insert(1, "value1".to_string());
196    /// store.insert(2, "value2".to_string());
197    /// store.retain(|key, value| *key == 1);
198    /// assert_eq!(store.len(), 1);
199    /// assert!(store.get(1).is_some());
200    /// assert!(store.get(2).is_none());
201    /// ```
202    pub fn retain(&mut self, mut f: impl FnMut(&K, &V) -> bool)
203    where
204        Lens: Writable,
205        K: Ord,
206    {
207        self.selector().mark_dirty_shallow();
208        self.selector().write_untracked().retain(|k, v| f(k, v));
209    }
210
211    /// Check if the BTreeMap contains a key. This method will track the store shallowly and only cause
212    /// re-runs when items are added or removed from the map, not when existing values are modified.
213    ///
214    /// # Example
215    /// ```rust, no_run
216    /// use dioxus_stores::*;
217    /// use dioxus::prelude::*;
218    /// use std::collections::BTreeMap;
219    /// let mut store = use_store(|| BTreeMap::new());
220    /// assert!(!store.contains_key(&0));
221    /// store.insert(0, "value".to_string());
222    /// assert!(store.contains_key(&0));
223    /// ```
224    pub fn contains_key<Q>(&self, key: &Q) -> bool
225    where
226        Q: ?Sized + Ord + 'static,
227        K: Borrow<Q> + Ord,
228    {
229        self.selector().track_shallow();
230        self.selector().peek().contains_key(key)
231    }
232
233    /// Get a store for the value associated with the given key. This method creates a new store scope
234    /// that tracks just changes to the value associated with the key.
235    ///
236    /// # Example
237    /// ```rust, no_run
238    /// use dioxus_stores::*;
239    /// use dioxus::prelude::*;
240    /// use std::collections::BTreeMap;
241    /// let mut store = use_store(|| BTreeMap::new());
242    /// assert!(store.get(0).is_none());
243    /// store.insert(0, "value".to_string());
244    /// assert_eq!(store.get(0).unwrap().cloned(), "value".to_string());
245    /// ```
246    pub fn get<Q>(self, key: Q) -> Option<Store<V, GetWrite<Q, Lens>>>
247    where
248        Q: Hash + Ord + 'static,
249        K: Borrow<Q> + Ord,
250    {
251        self.contains_key(&key).then(|| {
252            self.into_selector()
253                .hash_child_unmapped(key.borrow())
254                .map_writer(move |writer| GetWrite {
255                    index: key,
256                    write: writer,
257                })
258                .into()
259        })
260    }
261}
262
263/// A specific index in a `Readable` / `Writable` BTreeMap
264#[derive(Clone, Copy)]
265pub struct GetWrite<Index, Write> {
266    index: Index,
267    write: Write,
268}
269
270impl<Index, Write, K, V> Readable for GetWrite<Index, Write>
271where
272    Write: Readable<Target = BTreeMap<K, V>>,
273    Index: Ord + 'static,
274    K: Borrow<Index> + Ord + 'static,
275{
276    type Target = V;
277
278    type Storage = Write::Storage;
279
280    fn try_read_unchecked(&self) -> Result<dioxus_signals::ReadableRef<'static, Self>, BorrowError>
281    where
282        Self::Target: 'static,
283    {
284        self.write.try_read_unchecked().map(|value| {
285            Self::Storage::map(value, |value: &Write::Target| {
286                value
287                    .get(&self.index)
288                    .expect("Tried to access a key that does not exist")
289            })
290        })
291    }
292
293    fn try_peek_unchecked(&self) -> Result<dioxus_signals::ReadableRef<'static, Self>, BorrowError>
294    where
295        Self::Target: 'static,
296    {
297        self.write.try_peek_unchecked().map(|value| {
298            Self::Storage::map(value, |value: &Write::Target| {
299                value
300                    .get(&self.index)
301                    .expect("Tried to access a key that does not exist")
302            })
303        })
304    }
305
306    fn subscribers(&self) -> dioxus_core::Subscribers
307    where
308        Self::Target: 'static,
309    {
310        self.write.subscribers()
311    }
312}
313
314impl<Index, Write, K, V> Writable for GetWrite<Index, Write>
315where
316    Write: Writable<Target = BTreeMap<K, V>>,
317    Index: Ord + 'static,
318    K: Borrow<Index> + Ord + 'static,
319{
320    type WriteMetadata = Write::WriteMetadata;
321
322    fn try_write_unchecked(
323        &self,
324    ) -> Result<dioxus_signals::WritableRef<'static, Self>, BorrowMutError>
325    where
326        Self::Target: 'static,
327    {
328        self.write.try_write_unchecked().map(|value| {
329            WriteLock::map(value, |value: &mut Write::Target| {
330                value
331                    .get_mut(&self.index)
332                    .expect("Tried to access a key that does not exist")
333            })
334        })
335    }
336}
337
338impl<Index, Write, K, V> ::std::convert::From<Store<V, GetWrite<Index, Write>>>
339    for Store<V, WriteSignal<V>>
340where
341    Write::WriteMetadata: 'static,
342    Write: Writable<Target = BTreeMap<K, V>, Storage = UnsyncStorage> + 'static,
343    Index: Ord + 'static,
344    K: Borrow<Index> + Ord + 'static,
345    V: 'static,
346{
347    fn from(value: Store<V, GetWrite<Index, Write>>) -> Self {
348        value
349            .into_selector()
350            .map_writer(|writer| WriteSignal::new(writer))
351            .into()
352    }
353}
354
355impl<Index, Write, K, V> ::std::convert::From<Store<V, GetWrite<Index, Write>>> for ReadStore<V>
356where
357    Write: Readable<Target = BTreeMap<K, V>, Storage = UnsyncStorage> + 'static,
358    Index: Ord + 'static,
359    K: Borrow<Index> + Ord + 'static,
360    V: 'static,
361{
362    fn from(value: Store<V, GetWrite<Index, Write>>) -> Self {
363        value
364            .into_selector()
365            .map_writer(|writer| ReadSignal::new(writer))
366            .into()
367    }
368}