use crate::{read::Readable, ReadableRef, Signal, SignalData}; use dioxus_core::IntoDynNode; use std::ops::Deref; use crate::{default_impl, read_impls}; use dioxus_core::{prelude::IntoAttributeValue, ScopeId}; use generational_box::{Storage, UnsyncStorage}; /// A signal that can only be read from. pub struct ReadOnlySignal> = UnsyncStorage> { inner: Signal, } impl>> From> for ReadOnlySignal { fn from(inner: Signal) -> Self { Self { inner } } } impl ReadOnlySignal { /// Create a new read-only signal. #[track_caller] pub fn new(signal: Signal) -> Self { Self::new_maybe_sync(signal) } } impl>> ReadOnlySignal { /// Create a new read-only signal that is maybe sync. #[track_caller] pub fn new_maybe_sync(signal: Signal) -> Self { Self { inner: signal } } /// Get the scope that the signal was created in. pub fn origin_scope(&self) -> ScopeId { self.inner.origin_scope() } /// Get the id of the signal. pub fn id(&self) -> generational_box::GenerationalBoxId { self.inner.id() } #[doc(hidden)] /// This should only be used by the `rsx!` macro. pub fn __set(&mut self, value: T) { use crate::write::Writable; self.inner.set(value); } #[doc(hidden)] /// This should only be used by the `rsx!` macro. pub fn __take(&self) -> T { self.inner .manually_drop() .expect("Signal has already been dropped") } } impl>> Readable for ReadOnlySignal { type Target = T; type Storage = S; #[track_caller] fn try_read_unchecked( &self, ) -> Result, generational_box::BorrowError> { self.inner.try_read_unchecked() } /// Get the current value of the signal. **Unlike read, this will not subscribe the current scope to the signal which can cause parts of your UI to not update.** /// /// If the signal has been dropped, this will panic. #[track_caller] fn peek_unchecked(&self) -> S::Ref<'static, T> { self.inner.peek_unchecked() } } #[cfg(feature = "serialize")] impl>> serde::Serialize for ReadOnlySignal { fn serialize(&self, serializer: S) -> Result { self.read().serialize(serializer) } } #[cfg(feature = "serialize")] impl<'de, T: serde::Deserialize<'de> + 'static, Store: Storage>> serde::Deserialize<'de> for ReadOnlySignal { fn deserialize>(deserializer: D) -> Result { Ok(Self::new_maybe_sync(Signal::new_maybe_sync( T::deserialize(deserializer)?, ))) } } impl IntoAttributeValue for ReadOnlySignal where T: Clone + IntoAttributeValue, { fn into_value(self) -> dioxus_core::AttributeValue { self.with(|f| f.clone().into_value()) } } impl IntoDynNode for ReadOnlySignal where T: Clone + IntoDynNode, { fn into_dyn_node(self) -> dioxus_core::DynamicNode { self().into_dyn_node() } } impl>> PartialEq for ReadOnlySignal { fn eq(&self, other: &Self) -> bool { self.inner == other.inner } } impl> + 'static> Deref for ReadOnlySignal { type Target = dyn Fn() -> T; fn deref(&self) -> &Self::Target { Readable::deref_impl(self) } } read_impls!( ReadOnlySignal where S: Storage> ); default_impl!( ReadOnlySignal where S: Storage> ); impl>> Clone for ReadOnlySignal { fn clone(&self) -> Self { *self } } impl>> Copy for ReadOnlySignal {}