fix memo and resource caller information (#2443)

This commit is contained in:
Evan Almloff 2024-06-07 02:01:42 +02:00 committed by GitHub
parent 489758d5ba
commit 5e57779435
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 36 additions and 10 deletions

View file

@ -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);

View file

@ -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,

View file

@ -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> {