dioxus_signals/
map.rs

1use crate::{read::Readable, read_impls, ReadableExt, ReadableRef};
2use dioxus_core::{IntoAttributeValue, Subscribers};
3use generational_box::{AnyStorage, BorrowResult};
4use std::ops::Deref;
5
6/// A read only signal that has been mapped to a new type.
7pub struct MappedSignal<O: ?Sized, V, F = fn(&<V as Readable>::Target) -> &O> {
8    value: V,
9    map_fn: F,
10    _marker: std::marker::PhantomData<O>,
11}
12
13impl<V, O, F> Clone for MappedSignal<O, V, F>
14where
15    V: Readable + Clone,
16    F: Clone,
17{
18    fn clone(&self) -> Self {
19        MappedSignal {
20            value: self.value.clone(),
21            map_fn: self.map_fn.clone(),
22            _marker: std::marker::PhantomData,
23        }
24    }
25}
26
27impl<V, O, F> Copy for MappedSignal<O, V, F>
28where
29    V: Readable + Copy,
30    F: Copy,
31{
32}
33
34impl<V, O, F> MappedSignal<O, V, F>
35where
36    O: ?Sized,
37{
38    /// Create a new mapped signal.
39    pub fn new(value: V, map_fn: F) -> Self {
40        MappedSignal {
41            value,
42            map_fn,
43            _marker: std::marker::PhantomData,
44        }
45    }
46}
47
48impl<V, O, F> Readable for MappedSignal<O, V, F>
49where
50    O: ?Sized,
51    V: Readable,
52    V::Target: 'static,
53    F: Fn(&V::Target) -> &O,
54{
55    type Target = O;
56    type Storage = V::Storage;
57
58    fn try_read_unchecked(
59        &self,
60    ) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
61        let value = self.value.try_read_unchecked()?;
62        Ok(V::Storage::map(value, |v| (self.map_fn)(v)))
63    }
64
65    fn try_peek_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
66        let value = self.value.try_peek_unchecked()?;
67        Ok(V::Storage::map(value, |v| (self.map_fn)(v)))
68    }
69
70    fn subscribers(&self) -> Subscribers {
71        self.value.subscribers()
72    }
73}
74
75impl<V, O, F> IntoAttributeValue for MappedSignal<O, V, F>
76where
77    O: Clone + IntoAttributeValue + 'static,
78    V: Readable,
79    V::Target: 'static,
80    F: Fn(&V::Target) -> &O,
81{
82    fn into_value(self) -> dioxus_core::AttributeValue {
83        self.with(|f| f.clone().into_value())
84    }
85}
86
87impl<V, O, F> PartialEq for MappedSignal<O, V, F>
88where
89    O: ?Sized,
90    V: Readable + PartialEq,
91    F: PartialEq,
92{
93    fn eq(&self, other: &Self) -> bool {
94        self.value == other.value && self.map_fn == other.map_fn
95    }
96}
97
98/// Allow calling a signal with signal() syntax
99///
100/// Currently only limited to clone types, though could probably specialize for string/arc/rc
101impl<V, O, F> Deref for MappedSignal<O, V, F>
102where
103    O: Clone + 'static,
104    V: Readable + 'static,
105    F: Fn(&V::Target) -> &O + 'static,
106{
107    type Target = dyn Fn() -> O;
108
109    fn deref(&self) -> &Self::Target {
110        unsafe { ReadableExt::deref_impl(self) }
111    }
112}
113
114read_impls!(MappedSignal<T, V, F> where V: Readable<Target: 'static>, F: Fn(&V::Target) -> &T);