read_only_signal.rs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. use crate::{read::Readable, Signal, SignalData};
  2. use std::{mem::MaybeUninit, ops::Deref};
  3. use dioxus_core::{prelude::IntoAttributeValue, ScopeId};
  4. use generational_box::{Storage, UnsyncStorage};
  5. /// A signal that can only be read from.
  6. pub struct ReadOnlySignal<T: 'static, S: Storage<SignalData<T>> = UnsyncStorage> {
  7. inner: Signal<T, S>,
  8. }
  9. impl<T: 'static, S: Storage<SignalData<T>>> From<Signal<T, S>> for ReadOnlySignal<T, S> {
  10. fn from(inner: Signal<T, S>) -> Self {
  11. Self { inner }
  12. }
  13. }
  14. #[cfg(feature = "serde")]
  15. impl<T: serde::Serialize + 'static, Store: Storage<SignalData<T>>> serde::Serialize
  16. for ReadOnlySignal<T, Store>
  17. {
  18. fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
  19. self.read().serialize(serializer)
  20. }
  21. }
  22. #[cfg(feature = "serde")]
  23. impl<'de, T: serde::Deserialize<'de> + 'static, Store: Storage<SignalData<T>>>
  24. serde::Deserialize<'de> for ReadOnlySignal<T, Store>
  25. {
  26. fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
  27. Ok(Self::new_maybe_sync(Signal::new_maybe_sync(
  28. T::deserialize(deserializer)?,
  29. )))
  30. }
  31. }
  32. impl<T: 'static> ReadOnlySignal<T> {
  33. /// Create a new read-only signal.
  34. #[track_caller]
  35. pub fn new(signal: Signal<T>) -> Self {
  36. Self::new_maybe_sync(signal)
  37. }
  38. }
  39. impl<T: 'static, S: Storage<SignalData<T>>> ReadOnlySignal<T, S> {
  40. /// Create a new read-only signal that is maybe sync.
  41. #[track_caller]
  42. pub fn new_maybe_sync(signal: Signal<T, S>) -> Self {
  43. Self { inner: signal }
  44. }
  45. /// Get the scope that the signal was created in.
  46. pub fn origin_scope(&self) -> ScopeId {
  47. self.inner.origin_scope()
  48. }
  49. /// Get the id of the signal.
  50. pub fn id(&self) -> generational_box::GenerationalBoxId {
  51. self.inner.id()
  52. }
  53. }
  54. impl<T, S: Storage<SignalData<T>>> Readable<T> for ReadOnlySignal<T, S> {
  55. type Ref<R: ?Sized + 'static> = S::Ref<R>;
  56. fn map_ref<I, U: ?Sized, F: FnOnce(&I) -> &U>(ref_: Self::Ref<I>, f: F) -> Self::Ref<U> {
  57. S::map(ref_, f)
  58. }
  59. fn try_map_ref<I, U: ?Sized, F: FnOnce(&I) -> Option<&U>>(
  60. ref_: Self::Ref<I>,
  61. f: F,
  62. ) -> Option<Self::Ref<U>> {
  63. S::try_map(ref_, f)
  64. }
  65. /// Get the current value of the signal. This will subscribe the current scope to the signal. If you would like to read the signal without subscribing to it, you can use [`Self::peek`] instead.
  66. ///
  67. /// If the signal has been dropped, this will panic.
  68. #[track_caller]
  69. fn read(&self) -> S::Ref<T> {
  70. self.inner.read()
  71. }
  72. /// 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.**
  73. ///
  74. /// If the signal has been dropped, this will panic.
  75. fn peek(&self) -> S::Ref<T> {
  76. self.inner.peek()
  77. }
  78. }
  79. impl<T> IntoAttributeValue for ReadOnlySignal<T>
  80. where
  81. T: Clone + IntoAttributeValue,
  82. {
  83. fn into_value(self) -> dioxus_core::AttributeValue {
  84. self.with(|f| f.clone().into_value())
  85. }
  86. }
  87. impl<T: 'static, S: Storage<SignalData<T>>> PartialEq for ReadOnlySignal<T, S> {
  88. fn eq(&self, other: &Self) -> bool {
  89. self.inner == other.inner
  90. }
  91. }
  92. impl<T: Clone, S: Storage<SignalData<T>> + 'static> Deref for ReadOnlySignal<T, S> {
  93. type Target = dyn Fn() -> T;
  94. fn deref(&self) -> &Self::Target {
  95. // https://github.com/dtolnay/case-studies/tree/master/callable-types
  96. // First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit<Self>).
  97. let uninit_callable = MaybeUninit::<Self>::uninit();
  98. // Then move that value into the closure. We assume that the closure now has a in memory layout of Self.
  99. let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() }).clone();
  100. // Check that the size of the closure is the same as the size of Self in case the compiler changed the layout of the closure.
  101. let size_of_closure = std::mem::size_of_val(&uninit_closure);
  102. assert_eq!(size_of_closure, std::mem::size_of::<Self>());
  103. // Then cast the lifetime of the closure to the lifetime of &self.
  104. fn cast_lifetime<'a, T>(_a: &T, b: &'a T) -> &'a T {
  105. b
  106. }
  107. let reference_to_closure = cast_lifetime(
  108. {
  109. // The real closure that we will never use.
  110. &uninit_closure
  111. },
  112. // We transmute self into a reference to the closure. This is safe because we know that the closure has the same memory layout as Self so &Closure == &Self.
  113. unsafe { std::mem::transmute(self) },
  114. );
  115. // Cast the closure to a trait object.
  116. reference_to_closure as &Self::Target
  117. }
  118. }