Skip to content

Commit d8ddfc2

Browse files
authored
perf: use the Track trait for the Signal wrapper. (leptos-rs#3076)
1 parent c8acc3e commit d8ddfc2

File tree

5 files changed

+175
-246
lines changed

5 files changed

+175
-246
lines changed

reactive_graph/src/serde.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ impl<T: Serialize + 'static, St: Storage<T>> Serialize for ArcMemo<T, St> {
7575

7676
impl<T, St> Serialize for MaybeSignal<T, St>
7777
where
78-
T: Send + Sync + Serialize,
78+
T: Clone + Send + Sync + Serialize,
7979
St: Storage<SignalTypes<T, St>> + Storage<T>,
8080
{
8181
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

reactive_graph/src/signal/guards.rs

+43
Original file line numberDiff line numberDiff line change
@@ -623,3 +623,46 @@ where
623623
Display::fmt(&**self, f)
624624
}
625625
}
626+
627+
/// A wrapper that implements [`Deref`] and [`Borrow`] for itself.
628+
pub struct Derefable<T>(pub T);
629+
630+
impl<T> Clone for Derefable<T>
631+
where
632+
T: Clone,
633+
{
634+
fn clone(&self) -> Self {
635+
Derefable(self.0.clone())
636+
}
637+
}
638+
639+
impl<T> std::ops::Deref for Derefable<T> {
640+
type Target = T;
641+
fn deref(&self) -> &Self::Target {
642+
&self.0
643+
}
644+
}
645+
646+
impl<T> Borrow<T> for Derefable<T> {
647+
fn borrow(&self) -> &T {
648+
self.deref()
649+
}
650+
}
651+
652+
impl<T> PartialEq<T> for Derefable<T>
653+
where
654+
T: PartialEq,
655+
{
656+
fn eq(&self, other: &T) -> bool {
657+
self.deref() == other
658+
}
659+
}
660+
661+
impl<T> Display for Derefable<T>
662+
where
663+
T: Display,
664+
{
665+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
666+
Display::fmt(&**self, f)
667+
}
668+
}

reactive_graph/src/traits.rs

+28-13
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,20 @@ pub trait ReadUntracked: Sized + DefinedAt {
168168
self.try_read_untracked()
169169
.unwrap_or_else(unwrap_signal!(self))
170170
}
171+
172+
/// This is a backdoor to allow overriding the [`Read::try_read`] implementation despite it being auto implemented.
173+
///
174+
/// If your type contains a [`Signal`](crate::wrappers::read::Signal),
175+
/// call it's [`ReadUntracked::custom_try_read`] here, else return `None`.
176+
#[track_caller]
177+
fn custom_try_read(&self) -> Option<Option<Self::Value>> {
178+
None
179+
}
171180
}
172181

173182
/// Give read-only access to a signal's value by reference through a guard type,
174183
/// and subscribes the active reactive observer (an effect or computed) to changes in its value.
175-
pub trait Read {
184+
pub trait Read: DefinedAt {
176185
/// The guard type that will be returned, which can be dereferenced to the value.
177186
type Value: Deref;
178187

@@ -185,7 +194,9 @@ pub trait Read {
185194
/// # Panics
186195
/// Panics if you try to access a signal that has been disposed.
187196
#[track_caller]
188-
fn read(&self) -> Self::Value;
197+
fn read(&self) -> Self::Value {
198+
self.try_read().unwrap_or_else(unwrap_signal!(self))
199+
}
189200
}
190201

191202
impl<T> Read for T
@@ -195,13 +206,18 @@ where
195206
type Value = T::Value;
196207

197208
fn try_read(&self) -> Option<Self::Value> {
198-
self.track();
199-
self.try_read_untracked()
200-
}
201-
202-
fn read(&self) -> Self::Value {
203-
self.track();
204-
self.read_untracked()
209+
// The [`Read`] trait is auto implemented for types that implement [`ReadUntracked`] + [`Track`]. The [`Read`] trait then auto implements the [`With`] and [`Get`] traits too.
210+
//
211+
// This is a problem for e.g. the [`Signal`](crate::wrappers::read::Signal) type,
212+
// this type must use a custom [`Read::try_read`] implementation to avoid an unnecessary clone.
213+
//
214+
// This is a backdoor to allow overriding the [`Read::try_read`] implementation despite it being auto implemented.
215+
if let Some(custom) = self.custom_try_read() {
216+
custom
217+
} else {
218+
self.track();
219+
self.try_read_untracked()
220+
}
205221
}
206222
}
207223

@@ -307,14 +323,13 @@ pub trait With: DefinedAt {
307323

308324
impl<T> With for T
309325
where
310-
T: WithUntracked + Track,
326+
T: Read,
311327
{
312-
type Value = <T as WithUntracked>::Value;
328+
type Value = <<T as Read>::Value as Deref>::Target;
313329

314330
#[track_caller]
315331
fn try_with<U>(&self, fun: impl FnOnce(&Self::Value) -> U) -> Option<U> {
316-
self.track();
317-
self.try_with_untracked(fun)
332+
self.try_read().map(|val| fun(&val))
318333
}
319334
}
320335

0 commit comments

Comments
 (0)