瀏覽代碼

fix memo and resource caller information (#2443)

Evan Almloff 1 年之前
父節點
當前提交
5e57779435
共有 3 個文件被更改,包括 36 次插入10 次删除
  1. 11 2
      packages/hooks/src/use_resource.rs
  2. 15 8
      packages/signals/src/memo.rs
  3. 10 0
      packages/signals/src/signal.rs

+ 11 - 2
packages/hooks/src/use_resource.rs

@@ -68,15 +68,18 @@ use std::{cell::Cell, future::Future, rc::Rc};
 /// }
 /// ```
 #[must_use = "Consider using `cx.spawn` to run a future without reading its value"]
+#[track_caller]
 pub fn use_resource<T, F>(mut future: impl FnMut() -> F + 'static) -> Resource<T>
 where
     T: 'static,
     F: Future<Output = T> + 'static,
 {
+    let location = std::panic::Location::caller();
+
     let mut value = use_signal(|| None);
     let mut state = use_signal(|| UseResourceState::Pending);
     let (rc, changed) = use_hook(|| {
-        let (rc, changed) = ReactiveContext::new();
+        let (rc, changed) = ReactiveContext::new_with_origin(location);
         (rc, Rc::new(Cell::new(Some(changed))))
     });
 
@@ -92,7 +95,13 @@ where
 
             // Run each poll in the context of the reactive scope
             // This ensures the scope is properly subscribed to the future's dependencies
-            let res = future::poll_fn(|cx| rc.run_in(|| fut.poll_unpin(cx))).await;
+            let res = future::poll_fn(|cx| {
+                rc.run_in(|| {
+                    tracing::trace_span!("polling resource", location = %location)
+                        .in_scope(|| fut.poll_unpin(cx))
+                })
+            })
+            .await;
 
             // Set the value and state
             state.set(UseResourceState::Ready);

+ 15 - 8
packages/signals/src/memo.rs

@@ -5,7 +5,6 @@ use crate::{CopyValue, ReadOnlySignal};
 use std::{
     cell::RefCell,
     ops::Deref,
-    panic::Location,
     sync::{atomic::AtomicBool, Arc},
 };
 
@@ -36,7 +35,18 @@ where
 impl<T: 'static> Memo<T> {
     /// Create a new memo
     #[track_caller]
-    pub fn new(mut f: impl FnMut() -> T + 'static) -> Self
+    pub fn new(f: impl FnMut() -> T + 'static) -> Self
+    where
+        T: PartialEq,
+    {
+        Self::new_with_location(f, std::panic::Location::caller())
+    }
+
+    /// Create a new memo with an explicit location
+    pub fn new_with_location(
+        mut f: impl FnMut() -> T + 'static,
+        location: &'static std::panic::Location<'static>,
+    ) -> Self
     where
         T: PartialEq,
     {
@@ -50,11 +60,8 @@ impl<T: 'static> Memo<T> {
                 let _ = tx.unbounded_send(());
             }
         };
-        let rc = ReactiveContext::new_with_callback(
-            callback,
-            current_scope_id().unwrap(),
-            Location::caller(),
-        );
+        let rc =
+            ReactiveContext::new_with_callback(callback, current_scope_id().unwrap(), location);
 
         // Create a new signal in that context, wiring up its dependencies and subscribers
         let mut recompute = move || rc.run_in(&mut f);
@@ -64,7 +71,7 @@ impl<T: 'static> Memo<T> {
             dirty,
             callback: recompute,
         });
-        let state: Signal<T> = Signal::new(value);
+        let state: Signal<T> = Signal::new_with_caller(value, location);
 
         let memo = Memo {
             inner: state,

+ 10 - 0
packages/signals/src/signal.rs

@@ -91,6 +91,16 @@ impl<T: PartialEq + 'static> Signal<T> {
     pub fn memo(f: impl FnMut() -> T + 'static) -> Memo<T> {
         Memo::new(f)
     }
+
+    /// Creates a new unsync Selector with an explicit location. The selector will be run immediately and whenever any signal it reads changes.
+    ///
+    /// Selectors can be used to efficiently compute derived data from signals.
+    pub fn memo_with_location(
+        f: impl FnMut() -> T + 'static,
+        location: &'static std::panic::Location<'static>,
+    ) -> Memo<T> {
+        Memo::new_with_location(f, location)
+    }
 }
 
 impl<T: 'static, S: Storage<SignalData<T>>> Signal<T, S> {