signal.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. use std::{
  2. cell::{Ref, RefCell, RefMut},
  3. mem::MaybeUninit,
  4. ops::{Deref, DerefMut},
  5. rc::Rc,
  6. sync::Arc,
  7. };
  8. use dioxus_core::{
  9. prelude::{current_scope_id, has_context, provide_context, schedule_update_any},
  10. ScopeId, ScopeState,
  11. };
  12. use crate::{CopyValue, Effect};
  13. /// Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
  14. ///
  15. /// ```rust
  16. /// use dioxus::prelude::*;
  17. /// use dioxus_signals::*;
  18. ///
  19. /// fn App(cx: Scope) -> Element {
  20. /// let mut count = use_signal(cx, || 0);
  21. ///
  22. /// // 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.
  23. /// // The app component will never be rerendered in this example.
  24. /// render! { Child { state: count } }
  25. /// }
  26. ///
  27. /// #[component]
  28. /// fn Child(cx: Scope, state: Signal<u32>) -> Element {
  29. /// let state = *state;
  30. ///
  31. /// use_future!(cx, |()| async move {
  32. /// // Because the signal is a Copy type, we can use it in an async block without cloning it.
  33. /// *state.write() += 1;
  34. /// });
  35. ///
  36. /// render! {
  37. /// button {
  38. /// onclick: move |_| *state.write() += 1,
  39. /// "{state}"
  40. /// }
  41. /// }
  42. /// }
  43. /// ```
  44. pub fn use_signal<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) -> Signal<T> {
  45. *cx.use_hook(|| Signal::new(f()))
  46. }
  47. #[derive(Clone)]
  48. struct Unsubscriber {
  49. scope: ScopeId,
  50. subscribers: UnsubscriberArray,
  51. }
  52. type UnsubscriberArray = Rc<RefCell<Vec<Rc<RefCell<Vec<ScopeId>>>>>>;
  53. impl Drop for Unsubscriber {
  54. fn drop(&mut self) {
  55. for subscribers in self.subscribers.borrow().iter() {
  56. subscribers.borrow_mut().retain(|s| *s != self.scope);
  57. }
  58. }
  59. }
  60. fn current_unsubscriber() -> Unsubscriber {
  61. match has_context() {
  62. Some(rt) => rt,
  63. None => {
  64. let owner = Unsubscriber {
  65. scope: current_scope_id().expect("in a virtual dom"),
  66. subscribers: Default::default(),
  67. };
  68. provide_context(owner).expect("in a virtual dom")
  69. }
  70. }
  71. }
  72. pub(crate) struct SignalData<T> {
  73. pub(crate) subscribers: Rc<RefCell<Vec<ScopeId>>>,
  74. pub(crate) effect_subscribers: Rc<RefCell<Vec<Effect>>>,
  75. pub(crate) update_any: Arc<dyn Fn(ScopeId)>,
  76. pub(crate) value: T,
  77. }
  78. /// Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
  79. ///
  80. /// ```rust
  81. /// use dioxus::prelude::*;
  82. /// use dioxus_signals::*;
  83. ///
  84. /// #[component]
  85. /// fn App(cx: Scope) -> Element {
  86. /// let mut count = use_signal(cx, || 0);
  87. ///
  88. /// // 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.
  89. /// // The app component will never be rerendered in this example.
  90. /// render! { Child { state: count } }
  91. /// }
  92. ///
  93. /// #[component]
  94. /// fn Child(cx: Scope, state: Signal<u32>) -> Element {
  95. /// let state = *state;
  96. ///
  97. /// use_future!(cx, |()| async move {
  98. /// // Because the signal is a Copy type, we can use it in an async block without cloning it.
  99. /// *state.write() += 1;
  100. /// });
  101. ///
  102. /// render! {
  103. /// button {
  104. /// onclick: move |_| *state.write() += 1,
  105. /// "{state}"
  106. /// }
  107. /// }
  108. /// }
  109. /// ```
  110. pub struct Signal<T: 'static> {
  111. pub(crate) inner: CopyValue<SignalData<T>>,
  112. }
  113. #[cfg(feature = "serde")]
  114. impl<T: serde::Serialize + 'static> serde::Serialize for Signal<T> {
  115. fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
  116. self.read().serialize(serializer)
  117. }
  118. }
  119. #[cfg(feature = "serde")]
  120. impl<'de, T: serde::Deserialize<'de> + 'static> serde::Deserialize<'de> for Signal<T> {
  121. fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
  122. Ok(Self::new(T::deserialize(deserializer)?))
  123. }
  124. }
  125. impl<T: 'static> Signal<T> {
  126. /// Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
  127. pub fn new(value: T) -> Self {
  128. Self {
  129. inner: CopyValue::new(SignalData {
  130. subscribers: Default::default(),
  131. effect_subscribers: Default::default(),
  132. update_any: schedule_update_any().expect("in a virtual dom"),
  133. value,
  134. }),
  135. }
  136. }
  137. /// 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.
  138. pub fn new_in_scope(value: T, owner: ScopeId) -> Self {
  139. Self {
  140. inner: CopyValue::new_in_scope(
  141. SignalData {
  142. subscribers: Default::default(),
  143. effect_subscribers: Default::default(),
  144. update_any: schedule_update_any().expect("in a virtual dom"),
  145. value,
  146. },
  147. owner,
  148. ),
  149. }
  150. }
  151. /// Get the scope the signal was created in.
  152. pub fn origin_scope(&self) -> ScopeId {
  153. self.inner.origin_scope()
  154. }
  155. /// Get the current value of the signal. This will subscribe the current scope to the signal.
  156. /// If the signal has been dropped, this will panic.
  157. pub fn read(&self) -> Ref<T> {
  158. let inner = self.inner.read();
  159. if let Some(effect) = Effect::current() {
  160. let mut effect_subscribers = inner.effect_subscribers.borrow_mut();
  161. if !effect_subscribers.contains(&effect) {
  162. effect_subscribers.push(effect);
  163. }
  164. } else if let Some(current_scope_id) = current_scope_id() {
  165. // only subscribe if the vdom is rendering
  166. if dioxus_core::vdom_is_rendering() {
  167. tracing::trace!(
  168. "{:?} subscribed to {:?}",
  169. self.inner.value,
  170. current_scope_id
  171. );
  172. let mut subscribers = inner.subscribers.borrow_mut();
  173. if !subscribers.contains(&current_scope_id) {
  174. subscribers.push(current_scope_id);
  175. drop(subscribers);
  176. let unsubscriber = current_unsubscriber();
  177. inner.subscribers.borrow_mut().push(unsubscriber.scope);
  178. }
  179. }
  180. }
  181. Ref::map(inner, |v| &v.value)
  182. }
  183. /// Get a mutable reference to the signal's value.
  184. /// If the signal has been dropped, this will panic.
  185. pub fn write(&self) -> Write<'_, T> {
  186. let inner = self.inner.write();
  187. let borrow = RefMut::map(inner, |v| &mut v.value);
  188. Write {
  189. write: borrow,
  190. signal: SignalSubscriberDrop { signal: *self },
  191. }
  192. }
  193. fn update_subscribers(&self) {
  194. {
  195. let inner = self.inner.read();
  196. for &scope_id in &*inner.subscribers.borrow() {
  197. tracing::trace!(
  198. "Write on {:?} triggered update on {:?}",
  199. self.inner.value,
  200. scope_id
  201. );
  202. (inner.update_any)(scope_id);
  203. }
  204. }
  205. let subscribers = {
  206. let self_read = self.inner.read();
  207. let mut effects = self_read.effect_subscribers.borrow_mut();
  208. std::mem::take(&mut *effects)
  209. };
  210. for effect in subscribers {
  211. tracing::trace!(
  212. "Write on {:?} triggered effect {:?}",
  213. self.inner.value,
  214. effect
  215. );
  216. effect.try_run();
  217. }
  218. }
  219. /// Set the value of the signal. This will trigger an update on all subscribers.
  220. pub fn set(&self, value: T) {
  221. *self.write() = value;
  222. }
  223. /// Run a closure with a reference to the signal's value.
  224. /// If the signal has been dropped, this will panic.
  225. pub fn with<O>(&self, f: impl FnOnce(&T) -> O) -> O {
  226. let write = self.read();
  227. f(&*write)
  228. }
  229. /// Run a closure with a mutable reference to the signal's value.
  230. /// If the signal has been dropped, this will panic.
  231. pub fn with_mut<O>(&self, f: impl FnOnce(&mut T) -> O) -> O {
  232. let mut write = self.write();
  233. f(&mut *write)
  234. }
  235. }
  236. impl<T: Clone + 'static> Signal<T> {
  237. /// Get the current value of the signal. This will subscribe the current scope to the signal.
  238. /// If the signal has been dropped, this will panic.
  239. pub fn value(&self) -> T {
  240. self.read().clone()
  241. }
  242. }
  243. impl<T: 'static> PartialEq for Signal<T> {
  244. fn eq(&self, other: &Self) -> bool {
  245. self.inner == other.inner
  246. }
  247. }
  248. impl<T> Deref for Signal<T> {
  249. type Target = dyn Fn() -> Ref<'static, T>;
  250. fn deref(&self) -> &Self::Target {
  251. // https://github.com/dtolnay/case-studies/tree/master/callable-types
  252. // First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit<Self>).
  253. let uninit_callable = MaybeUninit::<Self>::uninit();
  254. // Then move that value into the closure. We assume that the closure now has a in memory layout of Self.
  255. let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() });
  256. // 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.
  257. let size_of_closure = std::mem::size_of_val(&uninit_closure);
  258. assert_eq!(size_of_closure, std::mem::size_of::<Self>());
  259. // Then cast the lifetime of the closure to the lifetime of &self.
  260. fn cast_lifetime<'a, T>(_a: &T, b: &'a T) -> &'a T {
  261. b
  262. }
  263. let reference_to_closure = cast_lifetime(
  264. {
  265. // The real closure that we will never use.
  266. &uninit_closure
  267. },
  268. // 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.
  269. unsafe { std::mem::transmute(self) },
  270. );
  271. // Cast the closure to a trait object.
  272. let reference_to_trait_object = reference_to_closure as &Self::Target;
  273. reference_to_trait_object
  274. }
  275. }
  276. struct SignalSubscriberDrop<T: 'static> {
  277. signal: Signal<T>,
  278. }
  279. impl<T: 'static> Drop for SignalSubscriberDrop<T> {
  280. fn drop(&mut self) {
  281. self.signal.update_subscribers();
  282. }
  283. }
  284. /// A mutable reference to a signal's value.
  285. pub struct Write<'a, T: 'static, I: 'static = T> {
  286. write: RefMut<'a, T>,
  287. signal: SignalSubscriberDrop<I>,
  288. }
  289. impl<'a, T: 'static, I: 'static> Write<'a, T, I> {
  290. /// Map the mutable reference to the signal's value to a new type.
  291. pub fn map<O>(myself: Self, f: impl FnOnce(&mut T) -> &mut O) -> Write<'a, O, I> {
  292. let Self { write, signal } = myself;
  293. Write {
  294. write: RefMut::map(write, f),
  295. signal,
  296. }
  297. }
  298. /// Try to map the mutable reference to the signal's value to a new type
  299. pub fn filter_map<O>(
  300. myself: Self,
  301. f: impl FnOnce(&mut T) -> Option<&mut O>,
  302. ) -> Option<Write<'a, O, I>> {
  303. let Self { write, signal } = myself;
  304. let write = RefMut::filter_map(write, f).ok();
  305. write.map(|write| Write { write, signal })
  306. }
  307. }
  308. impl<'a, T: 'static, I: 'static> Deref for Write<'a, T, I> {
  309. type Target = T;
  310. fn deref(&self) -> &Self::Target {
  311. &self.write
  312. }
  313. }
  314. impl<T, I> DerefMut for Write<'_, T, I> {
  315. fn deref_mut(&mut self) -> &mut Self::Target {
  316. &mut self.write
  317. }
  318. }
  319. /// A signal that can only be read from.
  320. pub struct ReadOnlySignal<T: 'static> {
  321. inner: Signal<T>,
  322. }
  323. impl<T: 'static> ReadOnlySignal<T> {
  324. /// Create a new read-only signal.
  325. pub fn new(signal: Signal<T>) -> Self {
  326. Self { inner: signal }
  327. }
  328. /// Get the scope that the signal was created in.
  329. pub fn origin_scope(&self) -> ScopeId {
  330. self.inner.origin_scope()
  331. }
  332. /// Get the current value of the signal. This will subscribe the current scope to the signal.
  333. pub fn read(&self) -> Ref<T> {
  334. self.inner.read()
  335. }
  336. /// Run a closure with a reference to the signal's value.
  337. pub fn with<O>(&self, f: impl FnOnce(&T) -> O) -> O {
  338. self.inner.with(f)
  339. }
  340. }
  341. impl<T: Clone + 'static> ReadOnlySignal<T> {
  342. /// Get the current value of the signal. This will subscribe the current scope to the signal.
  343. pub fn value(&self) -> T {
  344. self.read().clone()
  345. }
  346. }
  347. impl<T: 'static> PartialEq for ReadOnlySignal<T> {
  348. fn eq(&self, other: &Self) -> bool {
  349. self.inner == other.inner
  350. }
  351. }
  352. impl<T> Deref for ReadOnlySignal<T> {
  353. type Target = dyn Fn() -> Ref<'static, T>;
  354. fn deref(&self) -> &Self::Target {
  355. // https://github.com/dtolnay/case-studies/tree/master/callable-types
  356. // First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit<Self>).
  357. let uninit_callable = MaybeUninit::<Self>::uninit();
  358. // Then move that value into the closure. We assume that the closure now has a in memory layout of Self.
  359. let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() });
  360. // 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.
  361. let size_of_closure = std::mem::size_of_val(&uninit_closure);
  362. assert_eq!(size_of_closure, std::mem::size_of::<Self>());
  363. // Then cast the lifetime of the closure to the lifetime of &self.
  364. fn cast_lifetime<'a, T>(_a: &T, b: &'a T) -> &'a T {
  365. b
  366. }
  367. let reference_to_closure = cast_lifetime(
  368. {
  369. // The real closure that we will never use.
  370. &uninit_closure
  371. },
  372. // 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.
  373. unsafe { std::mem::transmute(self) },
  374. );
  375. // Cast the closure to a trait object.
  376. let reference_to_trait_object = reference_to_closure as &Self::Target;
  377. reference_to_trait_object
  378. }
  379. }