signal.rs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. use crate::MappedSignal;
  2. use std::{
  3. cell::RefCell,
  4. marker::PhantomData,
  5. mem::MaybeUninit,
  6. ops::{Deref, DerefMut},
  7. rc::Rc,
  8. sync::Arc,
  9. };
  10. use dioxus_core::{
  11. prelude::{
  12. current_scope_id, has_context, provide_context, schedule_update_any, use_hook,
  13. IntoAttributeValue,
  14. },
  15. ScopeId,
  16. };
  17. use generational_box::{
  18. GenerationalBoxId, Mappable, MappableMut, Storage, SyncStorage, UnsyncStorage,
  19. };
  20. use parking_lot::RwLock;
  21. use crate::{get_effect_ref, CopyValue, EffectStackRef, EFFECT_STACK};
  22. /// Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
  23. ///
  24. /// ```rust
  25. /// use dioxus::prelude::*;
  26. /// use dioxus_signals::*;
  27. ///
  28. /// fn App() -> Element {
  29. /// let mut count = use_signal(|| 0);
  30. ///
  31. /// // Because signals have automatic dependency tracking, if you never read them in a component, that component will not be re-rended when the signal is updated.
  32. /// // The app component will never be rerendered in this example.
  33. /// rsx! { Child { state: count } }
  34. /// }
  35. ///
  36. /// #[component]
  37. /// fn Child(state: Signal<u32>) -> Element {
  38. /// let state = *state;
  39. ///
  40. /// use_future( |()| async move {
  41. /// // Because the signal is a Copy type, we can use it in an async block without cloning it.
  42. /// *state.write() += 1;
  43. /// });
  44. ///
  45. /// rsx! {
  46. /// button {
  47. /// onclick: move |_| *state.write() += 1,
  48. /// "{state}"
  49. /// }
  50. /// }
  51. /// }
  52. /// ```
  53. #[track_caller]
  54. #[must_use]
  55. pub fn use_signal<T: 'static>(f: impl FnOnce() -> T) -> Signal<T, UnsyncStorage> {
  56. #[cfg(debug_assertions)]
  57. let caller = std::panic::Location::caller();
  58. use_hook(|| {
  59. Signal::new_with_caller(
  60. f(),
  61. #[cfg(debug_assertions)]
  62. caller,
  63. )
  64. })
  65. }
  66. /// Creates a new `Send + Sync`` Signal. Signals are a Copy state management solution with automatic dependency tracking.
  67. ///
  68. /// ```rust
  69. /// use dioxus::prelude::*;
  70. /// use dioxus_signals::*;
  71. ///
  72. /// fn App(cx: Scope) -> Element {
  73. /// let mut count = use_signal_sync(cx, || 0);
  74. ///
  75. /// // Because signals have automatic dependency tracking, if you never read them in a component, that component will not be re-rended when the signal is updated.
  76. /// // The app component will never be rerendered in this example.
  77. /// render! { Child { state: count } }
  78. /// }
  79. ///
  80. /// #[component]
  81. /// fn Child(cx: Scope, state: Signal<u32, SyncStorage>) -> Element {
  82. /// let state = *state;
  83. ///
  84. /// use_future!(cx, |()| async move {
  85. /// // This signal is Send + Sync, so we can use it in an another thread
  86. /// tokio::spawn(async move {
  87. /// // Because the signal is a Copy type, we can use it in an async block without cloning it.
  88. /// *state.write() += 1;
  89. /// }).await;
  90. /// });
  91. ///
  92. /// render! {
  93. /// button {
  94. /// onclick: move |_| *state.write() += 1,
  95. /// "{state}"
  96. /// }
  97. /// }
  98. /// }
  99. /// ```
  100. #[must_use]
  101. #[track_caller]
  102. pub fn use_signal_sync<T: Send + Sync + 'static>(f: impl FnOnce() -> T) -> Signal<T, SyncStorage> {
  103. #[cfg(debug_assertions)]
  104. let caller = std::panic::Location::caller();
  105. use_hook(|| {
  106. Signal::new_with_caller(
  107. f(),
  108. #[cfg(debug_assertions)]
  109. caller,
  110. )
  111. })
  112. }
  113. #[derive(Clone)]
  114. struct Unsubscriber {
  115. scope: ScopeId,
  116. subscribers: UnsubscriberArray,
  117. }
  118. type UnsubscriberArray = Rc<RefCell<Vec<Rc<RefCell<Vec<ScopeId>>>>>>;
  119. impl Drop for Unsubscriber {
  120. fn drop(&mut self) {
  121. for subscribers in self.subscribers.borrow().iter() {
  122. subscribers.borrow_mut().retain(|s| *s != self.scope);
  123. }
  124. }
  125. }
  126. fn current_unsubscriber() -> Unsubscriber {
  127. match has_context() {
  128. Some(rt) => rt,
  129. None => {
  130. let owner = Unsubscriber {
  131. scope: current_scope_id().expect("in a virtual dom"),
  132. subscribers: Default::default(),
  133. };
  134. provide_context(owner)
  135. }
  136. }
  137. }
  138. #[derive(Default)]
  139. pub(crate) struct SignalSubscribers {
  140. pub(crate) subscribers: Vec<ScopeId>,
  141. pub(crate) effect_subscribers: Vec<GenerationalBoxId>,
  142. }
  143. /// The data stored for tracking in a signal.
  144. pub struct SignalData<T> {
  145. pub(crate) subscribers: Arc<RwLock<SignalSubscribers>>,
  146. pub(crate) update_any: Arc<dyn Fn(ScopeId) + Sync + Send>,
  147. pub(crate) effect_ref: EffectStackRef,
  148. pub(crate) value: T,
  149. }
  150. /// Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
  151. ///
  152. /// ```rust
  153. /// use dioxus::prelude::*;
  154. /// use dioxus_signals::*;
  155. ///
  156. /// #[component]
  157. /// fn App() -> Element {
  158. /// let mut count = use_signal(|| 0);
  159. ///
  160. /// // Because signals have automatic dependency tracking, if you never read them in a component, that component will not be re-rended when the signal is updated.
  161. /// // The app component will never be rerendered in this example.
  162. /// rsx! { Child { state: count } }
  163. /// }
  164. ///
  165. /// #[component]
  166. /// fn Child(state: Signal<u32>) -> Element {
  167. /// let state = *state;
  168. ///
  169. /// use_future( |()| async move {
  170. /// // Because the signal is a Copy type, we can use it in an async block without cloning it.
  171. /// *state.write() += 1;
  172. /// });
  173. ///
  174. /// rsx! {
  175. /// button {
  176. /// onclick: move |_| *state.write() += 1,
  177. /// "{state}"
  178. /// }
  179. /// }
  180. /// }
  181. /// ```
  182. pub struct Signal<T: 'static, S: Storage<SignalData<T>> = UnsyncStorage> {
  183. pub(crate) inner: CopyValue<SignalData<T>, S>,
  184. }
  185. #[cfg(feature = "serde")]
  186. impl<T: serde::Serialize + 'static> serde::Serialize for Signal<T> {
  187. fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
  188. self.read().serialize(serializer)
  189. }
  190. }
  191. #[cfg(feature = "serde")]
  192. impl<'de, T: serde::Deserialize<'de> + 'static> serde::Deserialize<'de> for Signal<T> {
  193. fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
  194. Ok(Self::new(T::deserialize(deserializer)?))
  195. }
  196. }
  197. impl<T: 'static> Signal<T> {
  198. /// Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
  199. #[track_caller]
  200. pub fn new(value: T) -> Self {
  201. Self::new_maybe_sync(value)
  202. }
  203. /// Create a new signal with a custom owner scope. The signal will be dropped when the owner scope is dropped instead of the current scope.
  204. #[track_caller]
  205. pub fn new_in_scope(value: T, owner: ScopeId) -> Self {
  206. Self::new_maybe_sync_in_scope(value, owner)
  207. }
  208. }
  209. impl<T: 'static, S: Storage<SignalData<T>>> Signal<T, S> {
  210. /// Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
  211. #[track_caller]
  212. #[tracing::instrument(skip(value))]
  213. pub fn new_maybe_sync(value: T) -> Self {
  214. Self {
  215. inner: CopyValue::<SignalData<T>, S>::new_maybe_sync(SignalData {
  216. subscribers: Default::default(),
  217. update_any: schedule_update_any(),
  218. value,
  219. effect_ref: get_effect_ref(),
  220. }),
  221. }
  222. }
  223. /// Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
  224. fn new_with_caller(
  225. value: T,
  226. #[cfg(debug_assertions)] caller: &'static std::panic::Location<'static>,
  227. ) -> Self {
  228. Self {
  229. inner: CopyValue::new_with_caller(
  230. SignalData {
  231. subscribers: Default::default(),
  232. update_any: schedule_update_any(),
  233. value,
  234. effect_ref: get_effect_ref(),
  235. },
  236. #[cfg(debug_assertions)]
  237. caller,
  238. ),
  239. }
  240. }
  241. /// Create a new signal with a custom owner scope. The signal will be dropped when the owner scope is dropped instead of the current scope.
  242. #[track_caller]
  243. #[tracing::instrument(skip(value))]
  244. pub fn new_maybe_sync_in_scope(value: T, owner: ScopeId) -> Self {
  245. Self {
  246. inner: CopyValue::<SignalData<T>, S>::new_maybe_sync_in_scope(
  247. SignalData {
  248. subscribers: Default::default(),
  249. update_any: schedule_update_any(),
  250. value,
  251. effect_ref: get_effect_ref(),
  252. },
  253. owner,
  254. ),
  255. }
  256. }
  257. /// Get the scope the signal was created in.
  258. pub fn origin_scope(&self) -> ScopeId {
  259. self.inner.origin_scope()
  260. }
  261. /// 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.
  262. ///
  263. /// If the signal has been dropped, this will panic.
  264. #[track_caller]
  265. pub fn read(
  266. &self,
  267. ) -> <<S as Storage<SignalData<T>>>::Ref as Mappable<SignalData<T>>>::Mapped<T> {
  268. let inner = self.inner.read();
  269. if let Some(effect) = EFFECT_STACK.with(|stack| stack.current()) {
  270. let subscribers = inner.subscribers.read();
  271. if !subscribers.effect_subscribers.contains(&effect.inner.id()) {
  272. drop(subscribers);
  273. let mut subscribers = inner.subscribers.write();
  274. subscribers.effect_subscribers.push(effect.inner.id());
  275. }
  276. } else if let Some(current_scope_id) = current_scope_id() {
  277. // only subscribe if the vdom is rendering
  278. if dioxus_core::vdom_is_rendering() {
  279. tracing::trace!(
  280. "{:?} subscribed to {:?}",
  281. self.inner.value,
  282. current_scope_id
  283. );
  284. let subscribers = inner.subscribers.read();
  285. if !subscribers.subscribers.contains(&current_scope_id) {
  286. drop(subscribers);
  287. let mut subscribers = inner.subscribers.write();
  288. subscribers.subscribers.push(current_scope_id);
  289. let unsubscriber = current_unsubscriber();
  290. subscribers.subscribers.push(unsubscriber.scope);
  291. }
  292. }
  293. }
  294. S::Ref::map(inner, |v| &v.value)
  295. }
  296. /// 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.**
  297. ///
  298. /// If the signal has been dropped, this will panic.
  299. pub fn peek(
  300. &self,
  301. ) -> <<S as Storage<SignalData<T>>>::Ref as Mappable<SignalData<T>>>::Mapped<T> {
  302. let inner = self.inner.read();
  303. S::Ref::map(inner, |v| &v.value)
  304. }
  305. /// Get a mutable reference to the signal's value.
  306. ///
  307. /// If the signal has been dropped, this will panic.
  308. #[track_caller]
  309. pub fn write<'a>(
  310. &'a mut self,
  311. ) -> Write<T, <<S as Storage<SignalData<T>>>::Mut as MappableMut<SignalData<T>>>::Mapped<T>, S>
  312. {
  313. self.write_unchecked()
  314. }
  315. /// Write to the value through an immutable reference.
  316. ///
  317. /// This is public since it's useful in many scenarios, but we generally recommend mutation through [`Self::write`] instead.
  318. #[track_caller]
  319. pub fn write_unchecked(
  320. &self,
  321. ) -> Write<T, <<S as Storage<SignalData<T>>>::Mut as MappableMut<SignalData<T>>>::Mapped<T>, S>
  322. {
  323. let inner = self.inner.write();
  324. let borrow = S::Mut::map(inner, |v| &mut v.value);
  325. Write {
  326. write: borrow,
  327. signal: SignalSubscriberDrop { signal: *self },
  328. phantom: std::marker::PhantomData,
  329. }
  330. }
  331. fn update_subscribers(&self) {
  332. {
  333. let inner = self.inner.read();
  334. for &scope_id in &*inner.subscribers.read().subscribers {
  335. tracing::trace!(
  336. "Write on {:?} triggered update on {:?}",
  337. self.inner.value,
  338. scope_id
  339. );
  340. (inner.update_any)(scope_id);
  341. }
  342. }
  343. let self_read = &self.inner.read();
  344. let subscribers = {
  345. let effects = &mut self_read.subscribers.write().effect_subscribers;
  346. std::mem::take(&mut *effects)
  347. };
  348. let effect_ref = &self_read.effect_ref;
  349. for effect in subscribers {
  350. tracing::trace!(
  351. "Write on {:?} triggered effect {:?}",
  352. self.inner.value,
  353. effect
  354. );
  355. effect_ref.rerun_effect(effect);
  356. }
  357. }
  358. /// Set the value of the signal. This will trigger an update on all subscribers.
  359. #[track_caller]
  360. pub fn set(&mut self, value: T) {
  361. *self.write() = value;
  362. }
  363. /// Set the value of the signal without triggering an update on subscribers.
  364. ///
  365. /// todo: we should make it so setting while rendering doesn't trigger an update s
  366. pub fn set_untracked(&self, value: T) {
  367. let mut inner = self.inner.write();
  368. inner.value = value;
  369. }
  370. /// Run a closure with a reference to the signal's value.
  371. /// If the signal has been dropped, this will panic.
  372. #[track_caller]
  373. pub fn with<O>(&self, f: impl FnOnce(&T) -> O) -> O {
  374. let write = self.read();
  375. f(&*write)
  376. }
  377. /// Run a closure with a mutable reference to the signal's value.
  378. /// If the signal has been dropped, this will panic.
  379. #[track_caller]
  380. pub fn with_mut<O>(&mut self, f: impl FnOnce(&mut T) -> O) -> O {
  381. let mut write = self.write();
  382. f(&mut *write)
  383. }
  384. /// Map the signal to a new type.
  385. pub fn map<O>(
  386. self,
  387. f: impl Fn(&T) -> &O + 'static,
  388. ) -> MappedSignal<
  389. <<<S as generational_box::Storage<SignalData<T>>>::Ref as generational_box::Mappable<
  390. SignalData<T>,
  391. >>::Mapped<T> as generational_box::Mappable<T>>::Mapped<O>,
  392. > {
  393. MappedSignal::new(self, f)
  394. }
  395. /// Get the generational id of the signal.
  396. pub fn id(&self) -> generational_box::GenerationalBoxId {
  397. self.inner.id()
  398. }
  399. }
  400. impl<T> IntoAttributeValue for Signal<T>
  401. where
  402. T: Clone + IntoAttributeValue,
  403. {
  404. fn into_value(self) -> dioxus_core::AttributeValue {
  405. self.with(|f| f.clone().into_value())
  406. }
  407. }
  408. impl<T: Clone + 'static, S: Storage<SignalData<T>>> Signal<T, S> {
  409. /// Get the current value of the signal. This will subscribe the current scope to the signal.
  410. /// If the signal has been dropped, this will panic.
  411. #[track_caller]
  412. pub fn cloned(&self) -> T {
  413. self.read().clone()
  414. }
  415. }
  416. impl<S: Storage<SignalData<bool>>> Signal<bool, S> {
  417. /// Invert the boolean value of the signal. This will trigger an update on all subscribers.
  418. pub fn toggle(&mut self) {
  419. self.set(!self.cloned());
  420. }
  421. }
  422. impl<T: 'static, S: Storage<SignalData<T>>> PartialEq for Signal<T, S> {
  423. fn eq(&self, other: &Self) -> bool {
  424. self.inner == other.inner
  425. }
  426. }
  427. /// Allow calling a signal with signal() syntax
  428. ///
  429. /// Currently only limited to copy types, though could probably specialize for string/arc/rc
  430. impl<T: Copy, S: Storage<SignalData<T>> + 'static> Deref for Signal<T, S> {
  431. type Target = dyn Fn() -> T;
  432. fn deref(&self) -> &Self::Target {
  433. // https://github.com/dtolnay/case-studies/tree/master/callable-types
  434. // First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit<Self>).
  435. let uninit_callable = MaybeUninit::<Self>::uninit();
  436. // Then move that value into the closure. We assume that the closure now has a in memory layout of Self.
  437. let uninit_closure = move || *Self::read(unsafe { &*uninit_callable.as_ptr() });
  438. // 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.
  439. let size_of_closure = std::mem::size_of_val(&uninit_closure);
  440. assert_eq!(size_of_closure, std::mem::size_of::<Self>());
  441. // Then cast the lifetime of the closure to the lifetime of &self.
  442. fn cast_lifetime<'a, T>(_a: &T, b: &'a T) -> &'a T {
  443. b
  444. }
  445. let reference_to_closure = cast_lifetime(
  446. {
  447. // The real closure that we will never use.
  448. &uninit_closure
  449. },
  450. // 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.
  451. unsafe { std::mem::transmute(self) },
  452. );
  453. // Cast the closure to a trait object.
  454. reference_to_closure as &Self::Target
  455. }
  456. }
  457. struct SignalSubscriberDrop<T: 'static, S: Storage<SignalData<T>>> {
  458. signal: Signal<T, S>,
  459. }
  460. impl<T: 'static, S: Storage<SignalData<T>>> Drop for SignalSubscriberDrop<T, S> {
  461. fn drop(&mut self) {
  462. self.signal.update_subscribers();
  463. }
  464. }
  465. /// A mutable reference to a signal's value.
  466. ///
  467. /// T is the current type of the write
  468. /// B is the dynamically checked type of the write (RefMut)
  469. /// S is the storage type of the signal
  470. /// I is the type of the original signal
  471. pub struct Write<T: 'static, B: MappableMut<T>, S: Storage<SignalData<I>>, I: 'static = T> {
  472. write: B,
  473. signal: SignalSubscriberDrop<I, S>,
  474. phantom: std::marker::PhantomData<T>,
  475. }
  476. impl<T: 'static, B: MappableMut<T>, S: Storage<SignalData<I>>, I: 'static> Write<T, B, S, I> {
  477. /// Map the mutable reference to the signal's value to a new type.
  478. pub fn map<O>(myself: Self, f: impl FnOnce(&mut T) -> &mut O) -> Write<O, B::Mapped<O>, S, I> {
  479. let Self { write, signal, .. } = myself;
  480. Write {
  481. write: B::map(write, f),
  482. signal,
  483. phantom: std::marker::PhantomData,
  484. }
  485. }
  486. /// Try to map the mutable reference to the signal's value to a new type
  487. pub fn filter_map<O>(
  488. myself: Self,
  489. f: impl FnOnce(&mut T) -> Option<&mut O>,
  490. ) -> Option<Write<O, B::Mapped<O>, S, I>> {
  491. let Self { write, signal, .. } = myself;
  492. let write = B::try_map(write, f);
  493. write.map(|write| Write {
  494. write,
  495. signal,
  496. phantom: PhantomData,
  497. })
  498. }
  499. }
  500. impl<T: 'static, B: MappableMut<T>, S: Storage<SignalData<I>>, I: 'static> Deref
  501. for Write<T, B, S, I>
  502. {
  503. type Target = T;
  504. fn deref(&self) -> &Self::Target {
  505. &self.write
  506. }
  507. }
  508. impl<T, B: MappableMut<T>, S: Storage<SignalData<I>>, I> DerefMut for Write<T, B, S, I> {
  509. fn deref_mut(&mut self) -> &mut Self::Target {
  510. &mut self.write
  511. }
  512. }
  513. /// A signal that can only be read from.
  514. pub struct ReadOnlySignal<T: 'static, S: Storage<SignalData<T>> = UnsyncStorage> {
  515. inner: Signal<T, S>,
  516. }
  517. impl<T: 'static, S: Storage<SignalData<T>>> From<Signal<T, S>> for ReadOnlySignal<T, S> {
  518. fn from(inner: Signal<T, S>) -> Self {
  519. Self { inner }
  520. }
  521. }
  522. impl<T: 'static> ReadOnlySignal<T> {
  523. /// Create a new read-only signal.
  524. #[track_caller]
  525. pub fn new(signal: Signal<T>) -> Self {
  526. Self::new_maybe_sync(signal)
  527. }
  528. }
  529. impl<T: 'static, S: Storage<SignalData<T>>> ReadOnlySignal<T, S> {
  530. /// Create a new read-only signal that is maybe sync.
  531. #[track_caller]
  532. pub fn new_maybe_sync(signal: Signal<T, S>) -> Self {
  533. Self { inner: signal }
  534. }
  535. /// Get the scope that the signal was created in.
  536. pub fn origin_scope(&self) -> ScopeId {
  537. self.inner.origin_scope()
  538. }
  539. /// Get the current value of the signal. This will subscribe the current scope to the signal.
  540. ///
  541. /// If the signal has been dropped, this will panic.
  542. #[track_caller]
  543. pub fn read(
  544. &self,
  545. ) -> <<S as Storage<SignalData<T>>>::Ref as Mappable<SignalData<T>>>::Mapped<T> {
  546. self.inner.read()
  547. }
  548. /// 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.**
  549. ///
  550. /// If the signal has been dropped, this will panic.
  551. pub fn peek(
  552. &self,
  553. ) -> <<S as Storage<SignalData<T>>>::Ref as Mappable<SignalData<T>>>::Mapped<T> {
  554. self.inner.peek()
  555. }
  556. /// Run a closure with a reference to the signal's value.
  557. #[track_caller]
  558. pub fn with<O>(&self, f: impl FnOnce(&T) -> O) -> O {
  559. self.inner.with(f)
  560. }
  561. }
  562. impl<T: Clone + 'static, S: Storage<SignalData<T>>> ReadOnlySignal<T, S> {
  563. /// Get the current value of the signal. This will subscribe the current scope to the signal.
  564. pub fn value(&self) -> T {
  565. self.read().clone()
  566. }
  567. }
  568. impl<T: 'static, S: Storage<SignalData<T>>> PartialEq for ReadOnlySignal<T, S> {
  569. fn eq(&self, other: &Self) -> bool {
  570. self.inner == other.inner
  571. }
  572. }
  573. impl<T: Copy, S: Storage<SignalData<T>> + 'static> Deref for ReadOnlySignal<T, S> {
  574. type Target = dyn Fn() -> T;
  575. fn deref(&self) -> &Self::Target {
  576. // https://github.com/dtolnay/case-studies/tree/master/callable-types
  577. // First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit<Self>).
  578. let uninit_callable = MaybeUninit::<Self>::uninit();
  579. // Then move that value into the closure. We assume that the closure now has a in memory layout of Self.
  580. let uninit_closure = move || *Self::read(unsafe { &*uninit_callable.as_ptr() });
  581. // 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.
  582. let size_of_closure = std::mem::size_of_val(&uninit_closure);
  583. assert_eq!(size_of_closure, std::mem::size_of::<Self>());
  584. // Then cast the lifetime of the closure to the lifetime of &self.
  585. fn cast_lifetime<'a, T>(_a: &T, b: &'a T) -> &'a T {
  586. b
  587. }
  588. let reference_to_closure = cast_lifetime(
  589. {
  590. // The real closure that we will never use.
  591. &uninit_closure
  592. },
  593. // 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.
  594. unsafe { std::mem::transmute(self) },
  595. );
  596. // Cast the closure to a trait object.
  597. reference_to_closure as &Self::Target
  598. }
  599. }