From b9d179c4941a9b35511dee3df93399fa85e8b414 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 1 Jan 2024 10:44:21 -0600 Subject: [PATCH] add as_mapped_ref --- packages/signals/examples/iterator.rs | 2 +- packages/signals/examples/option.rs | 39 +++++++++++++++++++++++++++ packages/signals/src/impls.rs | 17 +++++++++--- packages/signals/src/map.rs | 22 +++++++-------- packages/signals/src/signal.rs | 6 ++--- packages/signals/tests/map.rs | 2 +- 6 files changed, 68 insertions(+), 20 deletions(-) create mode 100644 packages/signals/examples/option.rs diff --git a/packages/signals/examples/iterator.rs b/packages/signals/examples/iterator.rs index 24db7712f..2f6484b55 100644 --- a/packages/signals/examples/iterator.rs +++ b/packages/signals/examples/iterator.rs @@ -23,6 +23,6 @@ fn App(cx: Scope) -> Element { } #[component] -fn Child(cx: Scope, signal: SignalMap) -> Element { +fn Child(cx: Scope, signal: MappedSignal) -> Element { render! {"{signal:?}"} } diff --git a/packages/signals/examples/option.rs b/packages/signals/examples/option.rs new file mode 100644 index 000000000..10f41034c --- /dev/null +++ b/packages/signals/examples/option.rs @@ -0,0 +1,39 @@ +use dioxus::prelude::*; +use dioxus_signals::*; + +fn main() { + dioxus_desktop::launch(App); +} + +#[component] +fn App(cx: Scope) -> Element { + let signal = use_signal(cx, || Some(String::from("Hello"))); + + render! { + button { + onclick: move |_| { + let new_value = (!signal.read().is_some()).then(|| String::from("Hello")); + signal.set(new_value); + }, + "Swap" + } + button { + onclick: move |_| { + if let Some(value) = &mut *signal.write() { + value.push_str(" World"); + } + }, + "Change" + } + if let Some(item) = signal.as_mapped_ref(){ + render! { + Child { signal: item } + } + } + } +} + +#[component] +fn Child(cx: Scope, signal: MappedSignal) -> Element { + render! {"{signal:?}"} +} diff --git a/packages/signals/src/impls.rs b/packages/signals/src/impls.rs index f741b05ed..dc91eeae5 100644 --- a/packages/signals/src/impls.rs +++ b/packages/signals/src/impls.rs @@ -1,6 +1,6 @@ use crate::rt::CopyValue; use crate::signal::{ReadOnlySignal, Signal, Write}; -use crate::SignalMap; +use crate::MappedSignal; use generational_box::GenerationalRef; use generational_box::GenerationalRefMut; @@ -280,7 +280,7 @@ impl IntoIterator for Signal> { } } -/// An iterator over items in a `Signal>` that yields [`SignalMap`]s. +/// An iterator over items in a `Signal>` that yields [`MappedSignal`]s. pub struct MappedSignalIterator { index: usize, length: usize, @@ -288,7 +288,7 @@ pub struct MappedSignalIterator { } impl Iterator for MappedSignalIterator { - type Item = SignalMap; + type Item = MappedSignal; fn next(&mut self) -> Option { let index = self.index; @@ -303,7 +303,7 @@ impl Signal> { Write::filter_map(self.write(), |v| v.get_mut(index)) } - /// Create an iterator of [`SignalMap`]s over the inner vector. + /// Create an iterator of [`MappedSignal`]s over the inner vector. pub fn iter_signals(&self) -> MappedSignalIterator { MappedSignalIterator { index: 0, @@ -318,4 +318,13 @@ impl Signal> { pub fn as_mut(&self) -> Option>> { Write::filter_map(self.write(), |v| v.as_mut()) } + + /// Try to create a [`MappedSignal`] over the inner value. + pub fn as_mapped_ref(&self) -> Option> { + if self.read().is_some() { + Some(self.map(|v| v.as_ref().unwrap())) + } else { + None + } + } } diff --git a/packages/signals/src/map.rs b/packages/signals/src/map.rs index 5a9a4a817..13555e265 100644 --- a/packages/signals/src/map.rs +++ b/packages/signals/src/map.rs @@ -6,12 +6,12 @@ use std::fmt::Debug; use std::fmt::Display; /// A read only signal that has been mapped to a new type. -pub struct SignalMap { +pub struct MappedSignal { origin_scope: ScopeId, mapping: CopyValue GenerationalRef>>, } -impl SignalMap { +impl MappedSignal { /// Create a new mapped signal. pub fn new(signal: Signal, mapping: impl Fn(&T) -> &U + 'static) -> Self { Self { @@ -38,47 +38,47 @@ impl SignalMap { } } -impl SignalMap { +impl MappedSignal { /// Get the current value of the signal. This will subscribe the current scope to the signal. pub fn value(&self) -> U { self.read().clone() } } -impl PartialEq for SignalMap { +impl PartialEq for MappedSignal { fn eq(&self, other: &Self) -> bool { self.mapping == other.mapping } } -impl std::clone::Clone for SignalMap { +impl std::clone::Clone for MappedSignal { fn clone(&self) -> Self { *self } } -impl Copy for SignalMap {} +impl Copy for MappedSignal {} -impl Display for SignalMap { +impl Display for MappedSignal { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.with(|v| Display::fmt(v, f)) } } -impl Debug for SignalMap { +impl Debug for MappedSignal { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.with(|v| Debug::fmt(v, f)) } } -impl SignalMap> { +impl MappedSignal> { /// Read a value from the inner vector. pub fn get(&self, index: usize) -> Option> { GenerationalRef::filter_map(self.read(), |v| v.get(index)) } } -impl SignalMap> { +impl MappedSignal> { /// Unwraps the inner value and clones it. pub fn unwrap(&self) -> U where @@ -93,7 +93,7 @@ impl SignalMap> { } } -impl std::ops::Deref for SignalMap { +impl std::ops::Deref for MappedSignal { type Target = dyn Fn() -> GenerationalRef; fn deref(&self) -> &Self::Target { diff --git a/packages/signals/src/signal.rs b/packages/signals/src/signal.rs index aa94fbd4a..8a03af2a4 100644 --- a/packages/signals/src/signal.rs +++ b/packages/signals/src/signal.rs @@ -1,4 +1,4 @@ -use crate::SignalMap; +use crate::MappedSignal; use std::{ cell::RefCell, mem::MaybeUninit, @@ -307,8 +307,8 @@ impl Signal { } /// Map the signal to a new type. - pub fn map(self, f: impl Fn(&T) -> &O + 'static) -> SignalMap { - SignalMap::new(self, f) + pub fn map(self, f: impl Fn(&T) -> &O + 'static) -> MappedSignal { + MappedSignal::new(self, f) } } diff --git a/packages/signals/tests/map.rs b/packages/signals/tests/map.rs index 449e5e599..e93d2fed0 100644 --- a/packages/signals/tests/map.rs +++ b/packages/signals/tests/map.rs @@ -16,7 +16,7 @@ fn create_signals_global() { fn Child(cx: Scope) -> Element { let signal = create_without_cx(); - let mapped = SignalMap::new(signal, |v| v.as_bytes()); + let mapped = MappedSignal::new(signal, |v| v.as_bytes()); render! { "{signal:?}"