dioxus_shareables/
list.rs

1//! mod `list` - lists of shared values.
2//!
3//! See [`List`] for more info.
4
5use crate::shared::{Link, Shareable, Shared};
6use std::sync::Arc;
7
8/// A list of shareable values.
9///
10/// Using a `List<T>` rather than a `Vec<T>` allows components which use only one or two list items
11/// to get updated only when the specific list items they use are changed.
12///
13/// ```rust
14/// # use dioxus::prelude::*;
15/// use dioxus_shareables::{shareable, List, ListEntry};
16///
17/// shareable!(Numbers: List<usize> = [3, 5, 7].into_iter().collect());
18///
19/// #[allow(non_snake_case)]
20/// fn ListNumbers(cx: Scope) -> Element {
21///     let nums = Numbers.use_rw(&cx); // This component is updated when new items are added to or
22///                                     // removed from the list, but not when the individual list
23///                                     // items change.
24///     let w = nums.clone();
25///     cx.render(rsx! {
26///         ul {
27///             nums.read().iter().map(|n| rsx! { ListItem { num: n } })
28///         }
29///         button {
30///             onclick: move |_| {
31///                 let mut w = w.write();
32///                 let sum = w.iter().map(|n| *n.share().read()).sum();
33///                 w.push(sum)
34///             },
35///             "Sum"
36///         }
37///     })
38/// }
39///
40/// #[allow(non_snake_case)]
41/// #[inline_props]
42/// fn ListItem(cx: Scope, num: ListEntry<usize>) -> Element {
43///     let num = num.use_rw(&cx); // This component is updated when this specific entry in the
44///                                // list is modified.
45///     let w1 = num.clone();
46///     let w2 = num.clone();
47///     let num = num.read();
48///
49///     cx.render(rsx! {
50///         li {
51///             "{num}",
52///             button { onclick: move |_| *w1.write() += 1, "+" }
53///             button { onclick: move |_| *w2.write() -= 1, "-" }
54///         }
55///     })
56/// }
57///
58/// ```
59///
60/// `List` is a [`Vec`] internally, and the methods it implements therefore get their names and
61/// behavior from [`Vec`].
62///
63pub struct List<T>(Vec<ListEntry<T>>);
64
65#[allow(non_camel_case_types)]
66pub type share_entry_w<T> = fn(ListEntry<T>) -> Shared<T, super::W>;
67pub type Drain<'a, T> = std::iter::Map<std::vec::Drain<'a, ListEntry<T>>, share_entry_w<T>>;
68impl<T> List<T> {
69    /// See [`Vec::append`]
70    pub fn append(&mut self, o: &mut Self) {
71        self.0.append(&mut o.0)
72    }
73    /// See [`Vec::capacity`]
74    pub fn capacity(&self) -> usize {
75        self.0.capacity()
76    }
77    /// See [`Vec::clear`]
78    pub fn clear(&mut self) {
79        self.0.clear()
80    }
81    /// See [`Vec::dedup`]
82    pub fn dedup(&mut self)
83    where
84        T: PartialEq,
85    {
86        self.dedup_by(PartialEq::eq)
87    }
88    /// See [`Vec::dedup_by`]
89    pub fn dedup_by<F: FnMut(&T, &T) -> bool>(&mut self, mut f: F) {
90        self.0.dedup_by(|r, s| f(&r.0.borrow(), &s.0.borrow()))
91    }
92    /// See [`Vec::dedup_by_key`]
93    pub fn dedup_by_key<K: PartialEq, F: FnMut(&T) -> K>(&mut self, mut f: F) {
94        self.0.dedup_by(|r, s| f(&r.0.borrow()) == f(&s.0.borrow()))
95    }
96    /// See [`Vec::drain`]
97    pub fn drain<R: std::ops::RangeBounds<usize>>(&mut self, range: R) -> Drain<T>
98    where
99        T: 'static,
100    {
101        self.0.drain(range).map(|l| Shared::from_link(l.0))
102    }
103    /// See [`Vec::insert`]
104    pub fn insert(&mut self, index: usize, element: T) {
105        self.0.insert(index, ListEntry::new(element))
106    }
107    /// See [`Vec::is_empty`]
108    pub fn is_empty(&self) -> bool {
109        self.0.is_empty()
110    }
111    /// See [`Vec::len`]
112    pub fn len(&self) -> usize {
113        self.0.len()
114    }
115    /// See [`Vec::new`]
116    pub fn new() -> Self {
117        Self(Vec::new())
118    }
119    /// See [`Vec::pop`]
120    pub fn pop(&mut self) -> Option<Shared<T, super::W>> {
121        self.0.pop().map(|l| Shared::from_link(l.0))
122    }
123    /// See [`Vec::push`]
124    pub fn push(&mut self, value: T) {
125        self.0.push(ListEntry::new(value))
126    }
127    /// See [`Vec::remove`]
128    pub fn remove(&mut self, index: usize) -> Shared<T, super::W> {
129        Shared::from_link(self.0.remove(index).0)
130    }
131    /// See [`Vec::reserve`]
132    pub fn reserve(&mut self, additional: usize) {
133        self.0.reserve(additional)
134    }
135    /// See [`Vec::reserve_exact`]
136    pub fn reserve_exact(&mut self, additional: usize) {
137        self.0.reserve_exact(additional)
138    }
139    /// See [`Vec::resize`]
140    pub fn resize(&mut self, new_len: usize, t: T)
141    where
142        T: Clone,
143    {
144        self.0.resize_with(new_len, || ListEntry::new(t.clone()))
145    }
146    /// See [`Vec::resize_with`]
147    pub fn resize_with<F: FnMut() -> T>(&mut self, new_len: usize, mut f: F) {
148        self.0.resize_with(new_len, || ListEntry::new(f()))
149    }
150    /// See [`Vec::retain`]
151    pub fn retain<F: FnMut(&T) -> bool>(&mut self, mut f: F) {
152        self.0.retain(|l| f(&l.0.borrow()))
153    }
154    /// See [`Vec::retain`]
155    pub fn retain_mut<F: FnMut(&mut ListEntry<T>) -> bool>(&mut self, f: F)
156    where
157        T: 'static,
158    {
159        self.0.retain_mut(f)
160    }
161    /// See [`Vec::shrink_to`]
162    pub fn shrink_to(&mut self, min_capacity: usize) {
163        self.0.shrink_to(min_capacity)
164    }
165    /// See [`Vec::shrink_to_fit`]
166    pub fn shrink_to_fit(&mut self) {
167        self.0.shrink_to_fit()
168    }
169    /// See [`Vec::splice`]
170    pub fn splice<'a, R: std::ops::RangeBounds<usize>, I: 'a + IntoIterator<Item = T>>(
171        &'a mut self,
172        range: R,
173        replace_with: I,
174    ) -> impl 'a + Iterator<Item = Shared<T, super::W>>
175    where
176        T: 'static,
177    {
178        self.0
179            .splice(range, replace_with.into_iter().map(ListEntry::new))
180            .map(|l| Shared::from_link(l.0))
181    }
182    /// See [`Vec::split_off`]
183    pub fn split_off(&mut self, at: usize) -> Self {
184        Self(self.0.split_off(at))
185    }
186    /// See [`Vec::swap_remove`]
187    pub fn swap_remove(&mut self, index: usize) -> Shared<T, super::W> {
188        Shared::from_link(self.0.swap_remove(index).0)
189    }
190    /// See ['Vec::truncate`]
191    pub fn truncate(&mut self, len: usize) {
192        self.0.truncate(len)
193    }
194    /// See ['Vec::try_reserve`]
195    pub fn try_reserve(
196        &mut self,
197        additional: usize,
198    ) -> Result<(), std::collections::TryReserveError> {
199        self.0.try_reserve(additional)
200    }
201    /// See ['Vec::try_reserve_exact`]
202    pub fn try_reserve_exact(
203        &mut self,
204        additional: usize,
205    ) -> Result<(), std::collections::TryReserveError> {
206        self.0.try_reserve_exact(additional)
207    }
208    /// See ['Vec::with_capacity`]
209    pub fn with_capcity(capacity: usize) -> Self {
210        Self(Vec::with_capacity(capacity))
211    }
212    /// See [`[_]::binary_search`]
213    pub fn binary_search(&self, x: &T) -> Result<usize, usize>
214    where
215        T: Ord,
216    {
217        self.binary_search_by(|l| x.cmp(l))
218    }
219    /// See [`[_]::binary_search`]
220    pub fn binary_search_by<F: FnMut(&T) -> std::cmp::Ordering>(
221        &self,
222        mut f: F,
223    ) -> Result<usize, usize> {
224        self.0.binary_search_by(|l| f(&l.0.borrow()))
225    }
226    /// See [`[_]::binary_search_by_key`]
227    pub fn binary_search_by_key<B: std::cmp::Ord, F: FnMut(&T) -> B>(
228        &self,
229        b: &B,
230        mut f: F,
231    ) -> Result<usize, usize> {
232        self.0.binary_search_by_key(b, |l| f(&l.0.borrow()))
233    }
234    /// See [`[_]::contains`]
235    pub fn contains(&self, x: &T) -> bool
236    where
237        T: PartialEq,
238    {
239        self.0.iter().any(|l| x == &*l.0.borrow())
240    }
241    /// See [`[_]::ends_with`]
242    pub fn ends_with(&self, needle: &[T]) -> bool
243    where
244        T: PartialEq,
245    {
246        self.0.len() >= needle.len()
247            && std::iter::zip(self.0.iter().rev(), needle.iter().rev())
248                .all(|(l, x)| x == &*l.0.borrow())
249    }
250    /// See [`[_]::fill`]
251    ///
252    /// Note: This replaces items, rather than changing their value, so components which were
253    /// linked to the list before will not (necessarily) update.
254    pub fn fill(&mut self, t: T)
255    where
256        T: Clone,
257    {
258        self.0.fill_with(|| ListEntry::new(t.clone()))
259    }
260    /// See [`[_]::fill_with`]
261    ///
262    /// Note: This replaces items, rather than changing their value, so components which were
263    /// linked to the list before will not (necessarily) update.
264    pub fn fill_with<F: FnMut() -> T>(&mut self, mut f: F) {
265        self.0.fill_with(|| ListEntry::new(f()))
266    }
267    /// See [`[_]::first`]
268    pub fn first(&self) -> Option<ListEntry<T>> {
269        self.0.first().cloned()
270    }
271    /// See [`[_]::get`]
272    pub fn get(&self, index: usize) -> Option<ListEntry<T>> {
273        self.0.get(index).cloned()
274    }
275    /// See [`[_]::get_unchecked`]
276    ///
277    /// # Safety
278    ///   * The index must be in bounds for the slice, otherwise this method is u.b.
279    pub unsafe fn get_unchecked(&self, index: usize) -> ListEntry<T> {
280        self.0.get_unchecked(index).clone()
281    }
282    /// See [`[_]::iter`]
283    pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter {
284        self.into_iter()
285    }
286    /// See [`[_]::last`]
287    pub fn last(&self) -> Option<ListEntry<T>> {
288        self.0.last().cloned()
289    }
290    /// See [`[_]::partition_point`]
291    pub fn partition_point<P: FnMut(&T) -> bool>(&self, mut pred: P) -> usize {
292        self.0.partition_point(|l| pred(&l.0.borrow()))
293    }
294    /// See [`[_]::reverse`]
295    pub fn reverse(&mut self) {
296        self.0.reverse()
297    }
298    /// See [`[_]::rotate_left`]
299    pub fn rotate_left(&mut self, mid: usize) {
300        self.0.rotate_left(mid)
301    }
302    /// See [`[_]::rotate_right`]
303    pub fn rotate_right(&mut self, mid: usize) {
304        self.0.rotate_right(mid)
305    }
306    /// See [`[_]::sort`]
307    pub fn sort(&mut self)
308    where
309        T: Ord,
310    {
311        self.sort_by(Ord::cmp)
312    }
313    /// See [`[_]::sort_by`]
314    pub fn sort_by<F: FnMut(&T, &T) -> std::cmp::Ordering>(&mut self, mut f: F) {
315        self.0.sort_by(|a, b| f(&a.0.borrow(), &b.0.borrow()))
316    }
317    /// See [`[_]::sort_by`]
318    pub fn sort_by_cached_key<U: Ord, F: FnMut(&T) -> U>(&mut self, mut f: F) {
319        self.0.sort_by_cached_key(|a| f(&a.0.borrow()))
320    }
321    /// See [`[_]::sort_by`]
322    pub fn sort_by_key<U: Ord, F: FnMut(&T) -> U>(&mut self, mut f: F) {
323        self.0.sort_by_key(|a| f(&a.0.borrow()))
324    }
325    /// See [`[_]::sort`]
326    pub fn sort_unstable(&mut self)
327    where
328        T: Ord,
329    {
330        self.sort_unstable_by(Ord::cmp)
331    }
332    /// See [`[_]::sort_by`]
333    pub fn sort_unstable_by<F: FnMut(&T, &T) -> std::cmp::Ordering>(&mut self, mut f: F) {
334        self.0
335            .sort_unstable_by(|a, b| f(&a.0.borrow(), &b.0.borrow()))
336    }
337    /// See [`[_]::sort_by`]
338    pub fn sort_unstable_by_key<U: Ord, F: FnMut(&T) -> U>(&mut self, mut f: F) {
339        self.0.sort_unstable_by_key(|a| f(&a.0.borrow()))
340    }
341    /// See [`[_]::starts_with`]
342    pub fn starts_with(&self, needle: &[T]) -> bool
343    where
344        T: PartialEq,
345    {
346        self.0.len() >= needle.len()
347            && std::iter::zip(&self.0, needle).all(|(l, x)| x == &*l.0.borrow())
348    }
349    /// See [`[_]::swap`]
350    pub fn swap(&mut self, a: usize, b: usize) {
351        self.0.swap(a, b)
352    }
353}
354impl<T> Default for List<T> {
355    fn default() -> Self {
356        Self::new()
357    }
358}
359impl<'a, T> IntoIterator for &'a List<T> {
360    type Item = ListEntry<T>;
361    type IntoIter = std::iter::Cloned<std::slice::Iter<'a, ListEntry<T>>>;
362    fn into_iter(self) -> Self::IntoIter {
363        self.0.iter().cloned()
364    }
365}
366impl<T> FromIterator<T> for List<T> {
367    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
368        Self(iter.into_iter().map(ListEntry::new).collect())
369    }
370}
371impl<T> Extend<T> for List<T> {
372    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
373        self.0.extend(iter.into_iter().map(ListEntry::new))
374    }
375}
376impl<'a, T: 'a + Clone> Extend<&'a T> for List<T> {
377    fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
378        self.0.extend(iter.into_iter().cloned().map(ListEntry::new))
379    }
380}
381
382/// A pointer to an element from a [`List`]
383///
384/// Note that this cannot be used directly to get access to the value in the list. Instead, one
385/// must use either one of the methods [`use_w`](Self::use_w) or [`use_rw`](Self::use_rw).
386///
387/// `ListEntry` implements [`PartialEq`] _AS A POINTER ONLY_. This is so that the properties of a
388/// component depend only on which list entry is referenced, and not on the value.
389pub struct ListEntry<T>(Arc<Link<T>>);
390impl<T> PartialEq for ListEntry<T> {
391    fn eq(&self, o: &Self) -> bool {
392        Arc::ptr_eq(&self.0, &o.0)
393    }
394}
395impl<T> Clone for ListEntry<T> {
396    fn clone(&self) -> Self {
397        Self(self.0.clone())
398    }
399}
400impl<T> ListEntry<T> {
401    fn new(t: T) -> Self {
402        ListEntry(Arc::new(Link::new(t)))
403    }
404    /// Get a write-only pointer to the element.
405    ///
406    /// This is generally how an entry is accessed from the component which owns its `List`.
407    /// If the entry was passed down from a parent component, then you generally want to call
408    /// [`use_w`](Self::use_w) or [`use_rw`](Self::use_rw) instead.
409    pub fn share(&self) -> Shared<T, super::W> {
410        Shared::from_link(self.0.clone())
411    }
412    /// Get a write pointer to the element as a hook.
413    ///
414    /// This is the expected way to get write-only access to an entry when it is passed down from a
415    /// parent component. If you need to access an entry in the component which owns the list it
416    /// belongs to, then you generally need to use [`share`](Self::share) instead.
417    pub fn use_w<'a, P>(&self, cx: &dioxus_core::Scope<'a, P>) -> &'a mut Shared<T, super::W> {
418        let mut opt = Shareable(Some(self.0.clone()));
419        Shared::init(cx, &mut opt, || unreachable!(), super::W)
420    }
421    /// Get a read-write pointer to the element.
422    ///
423    /// Scope `cx` will be registered as needing update every time the referenced value changes.
424    ///
425    /// This is the expected ways to get read/write access an entry when it is passed down from a
426    /// parent component. If you need to access an entry in the component which owns the list it
427    /// belongs to, then you generally need to use [`share`](Self::share) instead.
428    pub fn use_rw<'a, P>(&self, cx: &dioxus_core::Scope<'a, P>) -> &'a mut Shared<T, super::RW> {
429        let mut opt = Shareable(Some(self.0.clone()));
430        Shared::init(cx, &mut opt, || unreachable!(), super::RW)
431    }
432}