signal.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  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. reference_to_closure as &Self::Target
  273. }
  274. }
  275. struct SignalSubscriberDrop<T: 'static> {
  276. signal: Signal<T>,
  277. }
  278. impl<T: 'static> Drop for SignalSubscriberDrop<T> {
  279. fn drop(&mut self) {
  280. self.signal.update_subscribers();
  281. }
  282. }
  283. /// A mutable reference to a signal's value.
  284. pub struct Write<'a, T: 'static, I: 'static = T> {
  285. write: RefMut<'a, T>,
  286. signal: SignalSubscriberDrop<I>,
  287. }
  288. impl<'a, T: 'static, I: 'static> Write<'a, T, I> {
  289. /// Map the mutable reference to the signal's value to a new type.
  290. pub fn map<O>(myself: Self, f: impl FnOnce(&mut T) -> &mut O) -> Write<'a, O, I> {
  291. let Self { write, signal } = myself;
  292. Write {
  293. write: RefMut::map(write, f),
  294. signal,
  295. }
  296. }
  297. /// Try to map the mutable reference to the signal's value to a new type
  298. pub fn filter_map<O>(
  299. myself: Self,
  300. f: impl FnOnce(&mut T) -> Option<&mut O>,
  301. ) -> Option<Write<'a, O, I>> {
  302. let Self { write, signal } = myself;
  303. let write = RefMut::filter_map(write, f).ok();
  304. write.map(|write| Write { write, signal })
  305. }
  306. }
  307. impl<'a, T: 'static, I: 'static> Deref for Write<'a, T, I> {
  308. type Target = T;
  309. fn deref(&self) -> &Self::Target {
  310. &self.write
  311. }
  312. }
  313. impl<T, I> DerefMut for Write<'_, T, I> {
  314. fn deref_mut(&mut self) -> &mut Self::Target {
  315. &mut self.write
  316. }
  317. }
  318. /// A signal that can only be read from.
  319. pub struct ReadOnlySignal<T: 'static> {
  320. inner: Signal<T>,
  321. }
  322. impl<T: 'static> ReadOnlySignal<T> {
  323. /// Create a new read-only signal.
  324. pub fn new(signal: Signal<T>) -> Self {
  325. Self { inner: signal }
  326. }
  327. /// Get the scope that the signal was created in.
  328. pub fn origin_scope(&self) -> ScopeId {
  329. self.inner.origin_scope()
  330. }
  331. /// Get the current value of the signal. This will subscribe the current scope to the signal.
  332. pub fn read(&self) -> Ref<T> {
  333. self.inner.read()
  334. }
  335. /// Run a closure with a reference to the signal's value.
  336. pub fn with<O>(&self, f: impl FnOnce(&T) -> O) -> O {
  337. self.inner.with(f)
  338. }
  339. }
  340. impl<T: Clone + 'static> ReadOnlySignal<T> {
  341. /// Get the current value of the signal. This will subscribe the current scope to the signal.
  342. pub fn value(&self) -> T {
  343. self.read().clone()
  344. }
  345. }
  346. impl<T: 'static> PartialEq for ReadOnlySignal<T> {
  347. fn eq(&self, other: &Self) -> bool {
  348. self.inner == other.inner
  349. }
  350. }
  351. impl<T> Deref for ReadOnlySignal<T> {
  352. type Target = dyn Fn() -> Ref<'static, T>;
  353. fn deref(&self) -> &Self::Target {
  354. // https://github.com/dtolnay/case-studies/tree/master/callable-types
  355. // First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit<Self>).
  356. let uninit_callable = MaybeUninit::<Self>::uninit();
  357. // Then move that value into the closure. We assume that the closure now has a in memory layout of Self.
  358. let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() });
  359. // 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.
  360. let size_of_closure = std::mem::size_of_val(&uninit_closure);
  361. assert_eq!(size_of_closure, std::mem::size_of::<Self>());
  362. // Then cast the lifetime of the closure to the lifetime of &self.
  363. fn cast_lifetime<'a, T>(_a: &T, b: &'a T) -> &'a T {
  364. b
  365. }
  366. let reference_to_closure = cast_lifetime(
  367. {
  368. // The real closure that we will never use.
  369. &uninit_closure
  370. },
  371. // 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.
  372. unsafe { std::mem::transmute(self) },
  373. );
  374. // Cast the closure to a trait object.
  375. reference_to_closure as &Self::Target
  376. }
  377. }