diff --git a/packages/signals/src/effect.rs b/packages/signals/src/effect.rs index 81f22e7bb..c8fb84258 100644 --- a/packages/signals/src/effect.rs +++ b/packages/signals/src/effect.rs @@ -54,7 +54,7 @@ pub(crate) fn get_effect_ref() -> EffectStackRef { while let Some(id) = receiver.next().await { EFFECT_STACK.with(|stack| { let effect_mapping = stack.effect_mapping.read(); - if let Some(effect) = effect_mapping.get(&id) { + if let Some(mut effect) = effect_mapping.get(&id).copied() { tracing::trace!("Rerunning effect: {:?}", id); effect.try_run(); } else { @@ -126,7 +126,7 @@ impl Effect { /// /// The signal will be owned by the current component and will be dropped when the component is dropped. pub fn new(callback: impl FnMut() + 'static) -> Self { - let myself = Self { + let mut myself = Self { source: current_scope_id().expect("in a virtual dom"), inner: EffectInner::new(Box::new(callback)), }; @@ -145,7 +145,7 @@ impl Effect { } /// Run the effect callback immediately. Returns `true` if the effect was run. Returns `false` is the effect is dead. - pub fn try_run(&self) { + pub fn try_run(&mut self) { tracing::trace!("Running effect: {:?}", self); if let Ok(mut inner) = self.inner.try_write() { { diff --git a/packages/signals/src/rt.rs b/packages/signals/src/rt.rs index 0cb8f1992..b8dd18247 100644 --- a/packages/signals/src/rt.rs +++ b/packages/signals/src/rt.rs @@ -142,7 +142,6 @@ impl> CopyValue { /// Try to read the value. If the value has been dropped, this will return None. #[track_caller] - pub fn try_read(&self) -> Result { self.value.try_read() } @@ -155,10 +154,14 @@ impl> CopyValue { /// Try to write the value. If the value has been dropped, this will return None. #[track_caller] - pub fn try_write(&self) -> Result { + pub fn try_write(&mut self) -> Result { self.value.try_write() } + /// Write the value without any lifetime hints. If the value has been dropped, this will panic. + /// + /// Note: This is completely safe because the value is stored in a generational box. The lifetime that normally is passed to the returned reference is only used as a hint to user to prevent runtime overlapping borrow panics. + #[track_caller] pub fn write_unchecked(&self) -> S::Mut { self.value.write() } @@ -170,17 +173,20 @@ impl> CopyValue { } /// Set the value. If the value has been dropped, this will panic. + #[track_caller] pub fn set(&self, value: T) { self.value.set(value); } /// Run a function with a reference to the value. If the value has been dropped, this will panic. + #[track_caller] pub fn with(&self, f: impl FnOnce(&T) -> O) -> O { let write = self.read(); f(&*write) } /// Run a function with a mutable reference to the value. If the value has been dropped, this will panic. + #[track_caller] pub fn with_mut(&self, f: impl FnOnce(&mut T) -> O) -> O { let mut write = self.write(); f(&mut *write) @@ -214,7 +220,7 @@ impl> Deref for CopyValue { // First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit). let uninit_callable = MaybeUninit::::uninit(); // Then move that value into the closure. We assume that the closure now has a in memory layout of Self. - let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() }).clone(); + let uninit_closure = move || *Self::read(unsafe { &*uninit_callable.as_ptr() }); // 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. let size_of_closure = std::mem::size_of_val(&uninit_closure);