signal.rs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. use crate::read::Readable;
  2. use crate::write::Writable;
  3. use crate::Write;
  4. use dioxus_core::prelude::{IntoAttributeValue, ScopeId};
  5. use generational_box::{AnyStorage, GenerationalRef, UnsyncStorage};
  6. use std::{cell::Ref, mem::MaybeUninit, ops::Deref};
  7. use super::get_global_context;
  8. use crate::{MappedSignal, Signal};
  9. /// A signal that can be accessed from anywhere in the application and created in a static
  10. pub struct GlobalSignal<T> {
  11. initializer: fn() -> T,
  12. }
  13. impl<T: 'static> GlobalSignal<T> {
  14. /// Create a new global signal with the given initializer.
  15. pub const fn new(initializer: fn() -> T) -> GlobalSignal<T> {
  16. GlobalSignal { initializer }
  17. }
  18. /// Get the signal that backs this global.
  19. pub fn signal(&self) -> Signal<T> {
  20. let key = self as *const _ as *const ();
  21. let context = get_global_context();
  22. let read = context.signal.borrow();
  23. match read.get(&key) {
  24. Some(signal) => *signal.downcast_ref::<Signal<T>>().unwrap(),
  25. None => {
  26. drop(read);
  27. // Constructors are always run in the root scope
  28. // The signal also exists in the root scope
  29. let value = ScopeId::ROOT.in_runtime(self.initializer);
  30. let signal = Signal::new_in_scope(value, ScopeId::ROOT);
  31. let entry = context.signal.borrow_mut().insert(key, Box::new(signal));
  32. debug_assert!(entry.is_none(), "Global signal already exists");
  33. signal
  34. }
  35. }
  36. }
  37. /// Write this value
  38. pub fn write(&self) -> Write<T, UnsyncStorage> {
  39. self.signal().write()
  40. }
  41. /// Get the scope the signal was created in.
  42. pub fn origin_scope(&self) -> ScopeId {
  43. ScopeId::ROOT
  44. }
  45. /// Run a closure with a mutable reference to the signal's value.
  46. /// If the signal has been dropped, this will panic.
  47. #[track_caller]
  48. pub fn with_mut<O>(&self, f: impl FnOnce(&mut T) -> O) -> O {
  49. self.signal().with_mut(f)
  50. }
  51. /// Map the signal to a new type.
  52. pub fn map<O>(
  53. &self,
  54. f: impl Fn(&T) -> &O + 'static,
  55. ) -> MappedSignal<GenerationalRef<Ref<'static, O>>> {
  56. MappedSignal::new(self.signal(), f)
  57. }
  58. /// Get the generational id of the signal.
  59. pub fn id(&self) -> generational_box::GenerationalBoxId {
  60. self.signal().id()
  61. }
  62. }
  63. impl<T: 'static> Readable<T> for GlobalSignal<T> {
  64. type Ref<R: ?Sized + 'static> = generational_box::GenerationalRef<std::cell::Ref<'static, R>>;
  65. fn map_ref<I, U: ?Sized, F: FnOnce(&I) -> &U>(ref_: Self::Ref<I>, f: F) -> Self::Ref<U> {
  66. <UnsyncStorage as AnyStorage>::map(ref_, f)
  67. }
  68. fn try_map_ref<I, U: ?Sized, F: FnOnce(&I) -> Option<&U>>(
  69. ref_: Self::Ref<I>,
  70. f: F,
  71. ) -> Option<Self::Ref<U>> {
  72. <UnsyncStorage as AnyStorage>::try_map(ref_, f)
  73. }
  74. #[track_caller]
  75. fn read(&self) -> Self::Ref<T> {
  76. self.signal().read()
  77. }
  78. #[track_caller]
  79. fn peek(&self) -> Self::Ref<T> {
  80. self.signal().peek()
  81. }
  82. }
  83. impl<T: 'static> Writable<T> for GlobalSignal<T> {
  84. type Mut<R: ?Sized + 'static> = Write<R, UnsyncStorage>;
  85. fn map_mut<I, U: ?Sized + 'static, F: FnOnce(&mut I) -> &mut U>(
  86. ref_: Self::Mut<I>,
  87. f: F,
  88. ) -> Self::Mut<U> {
  89. Write::map(ref_, f)
  90. }
  91. fn try_map_mut<I: 'static, U: ?Sized + 'static, F: FnOnce(&mut I) -> Option<&mut U>>(
  92. ref_: Self::Mut<I>,
  93. f: F,
  94. ) -> Option<Self::Mut<U>> {
  95. Write::filter_map(ref_, f)
  96. }
  97. #[track_caller]
  98. fn try_write(&self) -> Result<Self::Mut<T>, generational_box::BorrowMutError> {
  99. self.signal().try_write()
  100. }
  101. }
  102. impl<T: 'static> IntoAttributeValue for GlobalSignal<T>
  103. where
  104. T: Clone + IntoAttributeValue,
  105. {
  106. fn into_value(self) -> dioxus_core::AttributeValue {
  107. self.signal().into_value()
  108. }
  109. }
  110. impl<T: 'static> PartialEq for GlobalSignal<T> {
  111. fn eq(&self, other: &Self) -> bool {
  112. std::ptr::eq(self, other)
  113. }
  114. }
  115. /// Allow calling a signal with signal() syntax
  116. ///
  117. /// Currently only limited to copy types, though could probably specialize for string/arc/rc
  118. impl<T: Clone + 'static> Deref for GlobalSignal<T> {
  119. type Target = dyn Fn() -> T;
  120. fn deref(&self) -> &Self::Target {
  121. // https://github.com/dtolnay/case-studies/tree/master/callable-types
  122. // First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit<Self>).
  123. let uninit_callable = MaybeUninit::<Self>::uninit();
  124. // Then move that value into the closure. We assume that the closure now has a in memory layout of Self.
  125. let uninit_closure = move || {
  126. <GlobalSignal<T> as Readable<T>>::read(unsafe { &*uninit_callable.as_ptr() }).clone()
  127. };
  128. // 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.
  129. let size_of_closure = std::mem::size_of_val(&uninit_closure);
  130. assert_eq!(size_of_closure, std::mem::size_of::<Self>());
  131. // Then cast the lifetime of the closure to the lifetime of &self.
  132. fn cast_lifetime<'a, T>(_a: &T, b: &'a T) -> &'a T {
  133. b
  134. }
  135. let reference_to_closure = cast_lifetime(
  136. {
  137. // The real closure that we will never use.
  138. &uninit_closure
  139. },
  140. // 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.
  141. unsafe { std::mem::transmute(self) },
  142. );
  143. // Cast the closure to a trait object.
  144. reference_to_closure as &Self::Target
  145. }
  146. }