AsyncSignal now keeps track if the it's loading.

This commit is contained in:
Filipe Rodrigues 2024-12-22 18:52:52 +00:00
parent 33d480aa3e
commit d4497e1935
Signed by: zenithsiz
SSH Key Fingerprint: SHA256:Mb5ppb3Sh7IarBO/sBTXLHbYEOz37hJAlslLQPPAPaU
6 changed files with 38 additions and 1 deletions

2
Cargo.lock generated
View File

@ -142,6 +142,7 @@ dependencies = [
"anyhow",
"duplicate",
"dynatos-reactive",
"dynatos-reactive-sync",
"dynatos-util",
"extend",
"tracing",
@ -158,6 +159,7 @@ dependencies = [
"extend",
"itertools",
"pin-project",
"scopeguard",
"tracing",
]

View File

@ -47,6 +47,7 @@ parking_lot = "0.12.3"
pin-project = "1.1.7"
proc-macro2 = "1.0.92"
quote = "1.0.37"
scopeguard = "1.2.0"
syn = "2.0.90"
tracing = "0.1.41"
tracing-subscriber = "0.3.19"

View File

@ -51,6 +51,14 @@ impl<F: Future<Output = Result<T, E>>, T, E> LoadableSignal<F> {
self.inner.has_polled()
}
/// Gets whether this future should is loading.
///
/// Returns `true` is [`Self::load`] is currently loading.
#[must_use]
pub fn is_loading(&self) -> bool {
self.inner.is_loading()
}
/// Loads this value asynchronously and returns the value
pub async fn load(&self) -> Result<BorrowRef<'_, T, E>, E>
where

View File

@ -13,6 +13,7 @@ duplicate = { workspace = true }
extend = { workspace = true }
itertools = { workspace = true }
pin-project = { workspace = true }
scopeguard = { workspace = true }
tracing = { workspace = true }
[lints]

View File

@ -77,6 +77,9 @@ struct Inner<F: Future> {
/// Whether we've been polled.
has_polled: AtomicBool,
/// Whether we're currently loading
is_loading: AtomicBool,
/// Value
value: OnceLock<F::Output>,
}
@ -104,7 +107,7 @@ impl<F: Future> AsyncSignal<F> {
Self::new_inner(fut, true)
}
/// Creates a new async signal from a future
/// Inner constructor
#[track_caller]
fn new_inner(fut: F, is_suspended: bool) -> Self {
let inner = Rc::pin(Inner {
@ -116,6 +119,7 @@ impl<F: Future> AsyncSignal<F> {
}),
is_suspended: AtomicBool::new(is_suspended),
has_polled: AtomicBool::new(false),
is_loading: AtomicBool::new(false),
value: OnceLock::new(),
});
Self { inner }
@ -138,6 +142,14 @@ impl<F: Future> AsyncSignal<F> {
self.inner.has_polled.load(atomic::Ordering::Acquire)
}
/// Gets whether this future should is loading.
///
/// Returns `true` is [`Self::load`] is currently loading.
#[must_use]
pub fn is_loading(&self) -> bool {
self.inner.is_loading.load(atomic::Ordering::Acquire)
}
/// Loads this value asynchronously and returns the value
pub async fn load(&self) -> &'_ F::Output {
// Gather subcribers before polling
@ -145,6 +157,12 @@ impl<F: Future> AsyncSignal<F> {
// instead of by thread.
self.inner.waker.trigger.gather_subscribers();
// Signal that we're loading, and defer setting otherwise at the end
self.inner.is_loading.store(true, atomic::Ordering::Release);
scopeguard::defer! {
self.inner.is_loading.store(false, atomic::Ordering::Release);
};
// Poll until we're loaded
future::poll_fn(|cx| match self.try_load(cx) {
Some(value) => Poll::Ready(value),

7
examples/Cargo.lock generated
View File

@ -156,6 +156,7 @@ dependencies = [
"extend",
"itertools",
"pin-project",
"scopeguard",
"tracing",
]
@ -527,6 +528,12 @@ dependencies = [
"web-sys",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.216"