Skip to main content

dioxus_stores/impls/
slice.rs

1//! Additional utilities for `Vec` stores.
2
3use std::{iter::FusedIterator, panic::Location};
4
5use crate::{ReadStore, impls::index::IndexSelector, store::Store};
6use dioxus_signals::{
7    AnyStorage, BorrowError, BorrowMutError, ReadSignal, Readable, ReadableExt, UnsyncStorage,
8    Writable, WriteLock, WriteSignal,
9};
10use generational_box::ValueDroppedError;
11
12impl<Lens, I> Store<Vec<I>, Lens>
13where
14    Lens: Readable<Target = Vec<I>> + 'static,
15    I: 'static,
16{
17    /// Returns the length of the slice. This will only track the shallow state of the slice.
18    /// It will only cause a re-run if the length of the slice could change.
19    ///
20    /// # Example
21    /// ```rust, no_run
22    /// use dioxus_stores::*;
23    /// let store = use_store(|| vec![1, 2, 3]);
24    /// assert_eq!(store.len(), 3);
25    /// ```
26    pub fn len(&self) -> usize {
27        self.selector().track_shallow();
28        self.selector().peek().len()
29    }
30
31    /// Checks if the slice is empty. This will only track the shallow state of the slice.
32    /// It will only cause a re-run if the length of the slice could change.
33    ///
34    /// # Example
35    /// ```rust, no_run
36    /// use dioxus_stores::*;
37    /// let store = use_store(|| vec![1, 2, 3]);
38    /// assert!(!store.is_empty());
39    /// ```
40    pub fn is_empty(&self) -> bool {
41        self.selector().track_shallow();
42        self.selector().peek().is_empty()
43    }
44
45    /// Returns an iterator over the items in the slice. This will only track the shallow state of the slice.
46    /// It will only cause a re-run if the length of the slice could change.
47    /// # Example
48    /// ```rust, no_run
49    /// use dioxus_stores::*;
50    /// let store = use_store(|| vec![1, 2, 3]);
51    /// for item in store.iter() {
52    ///     println!("{}", item);
53    /// }
54    /// ```
55    #[track_caller]
56    pub fn iter(
57        &self,
58    ) -> impl ExactSizeIterator<Item = Store<I, VecGetWrite<Lens>>>
59    + DoubleEndedIterator
60    + FusedIterator
61    + '_
62    where
63        Lens: Clone,
64    {
65        let location = Location::caller();
66        (0..self.len()).map(move |i| self.clone().get_unchecked_at(i, location))
67    }
68
69    /// Try to get an item from slice. This will only track the shallow state of the slice.
70    /// It will only cause a re-run if the length of the slice could change. The new store
71    /// will only update when the item at the index changes.
72    ///
73    /// # Example
74    /// ```rust, no_run
75    /// use dioxus_stores::*;
76    /// let store = use_store(|| vec![1, 2, 3]);
77    /// let indexed_store = store.get(1).unwrap();
78    /// // The indexed store can access the store methods of the indexed store.
79    /// assert_eq!(indexed_store(), 2);
80    /// ```
81    pub fn get(&self, index: usize) -> Option<Store<I, VecGetWrite<Lens>>>
82    where
83        Lens: Clone,
84    {
85        if index >= self.len() {
86            None
87        } else {
88            Some(self.clone().get_unchecked(index))
89        }
90    }
91
92    /// Get a store for the item at the given index without checking if it is in bounds.
93    ///
94    /// This is not unsafe, but reads will return a [BorrowError::Dropped] error if the index is out of bounds.
95    #[track_caller]
96    pub fn get_unchecked(self, index: usize) -> Store<I, VecGetWrite<Lens>> {
97        self.get_unchecked_at(index, Location::caller())
98    }
99
100    fn get_unchecked_at(
101        self,
102        index: usize,
103        location: &'static Location<'static>,
104    ) -> Store<I, VecGetWrite<Lens>> {
105        <Vec<I>>::scope_selector(self.into_selector(), &index)
106            .map_writer(move |write| VecGetWrite {
107                index,
108                write,
109                created: location,
110            })
111            .into()
112    }
113}
114
115/// A specific index in a `Readable` / `Writable` Vec that uses safe `.get()` / `.get_mut()` access.
116#[derive(Clone, Copy)]
117pub struct VecGetWrite<Write> {
118    index: usize,
119    write: Write,
120    created: &'static Location<'static>,
121}
122
123impl<Write, T> Readable for VecGetWrite<Write>
124where
125    Write: Readable<Target = Vec<T>>,
126    T: 'static,
127{
128    type Target = T;
129    type Storage = Write::Storage;
130
131    fn try_read_unchecked(&self) -> Result<dioxus_signals::ReadableRef<'static, Self>, BorrowError>
132    where
133        Self::Target: 'static,
134    {
135        self.write.try_read_unchecked().and_then(|value| {
136            let index = self.index;
137            Self::Storage::try_map(value, move |value: &Vec<T>| value.get(index))
138                .ok_or_else(|| BorrowError::Dropped(ValueDroppedError::new(self.created)))
139        })
140    }
141
142    fn try_peek_unchecked(&self) -> Result<dioxus_signals::ReadableRef<'static, Self>, BorrowError>
143    where
144        Self::Target: 'static,
145    {
146        self.write.try_peek_unchecked().and_then(|value| {
147            let index = self.index;
148            Self::Storage::try_map(value, move |value: &Vec<T>| value.get(index))
149                .ok_or_else(|| BorrowError::Dropped(ValueDroppedError::new(self.created)))
150        })
151    }
152
153    fn subscribers(&self) -> dioxus_core::Subscribers
154    where
155        Self::Target: 'static,
156    {
157        self.write.subscribers()
158    }
159}
160
161impl<Write, T> Writable for VecGetWrite<Write>
162where
163    Write: Writable<Target = Vec<T>>,
164    T: 'static,
165{
166    type WriteMetadata = Write::WriteMetadata;
167
168    fn try_write_unchecked(
169        &self,
170    ) -> Result<dioxus_signals::WritableRef<'static, Self>, BorrowMutError>
171    where
172        Self::Target: 'static,
173    {
174        self.write.try_write_unchecked().and_then(|value| {
175            let index = self.index;
176            WriteLock::filter_map(value, move |value: &mut Vec<T>| value.get_mut(index))
177                .ok_or_else(|| BorrowMutError::Dropped(ValueDroppedError::new(self.created)))
178        })
179    }
180}
181
182impl<T, Write> ::std::convert::From<Store<T, VecGetWrite<Write>>> for Store<T, WriteSignal<T>>
183where
184    Write: Writable<Target = Vec<T>, Storage = UnsyncStorage> + 'static,
185    Write::WriteMetadata: 'static,
186    T: 'static,
187{
188    fn from(value: Store<T, VecGetWrite<Write>>) -> Self {
189        value
190            .into_selector()
191            .map_writer(|writer| WriteSignal::new(writer))
192            .into()
193    }
194}
195
196impl<T, Write> ::std::convert::From<Store<T, VecGetWrite<Write>>> for ReadStore<T>
197where
198    Write: Readable<Target = Vec<T>, Storage = UnsyncStorage> + 'static,
199    T: 'static,
200{
201    fn from(value: Store<T, VecGetWrite<Write>>) -> Self {
202        value
203            .into_selector()
204            .map_writer(|writer| ReadSignal::new(writer))
205            .into()
206    }
207}