Skip to content

Commit

Permalink
feat: better error handling for ScopedFuture
Browse files Browse the repository at this point in the history
  • Loading branch information
gbj committed Sep 29, 2023
1 parent f7adf6f commit 2b3c755
Showing 1 changed file with 24 additions and 18 deletions.
42 changes: 24 additions & 18 deletions leptos_reactive/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use std::{
rc::Rc,
task::Poll,
};
use thiserror::Error;

pub(crate) type PinnedFuture<T> = Pin<Box<dyn Future<Output = T>>>;

Expand Down Expand Up @@ -1494,19 +1495,22 @@ pub struct ScopedFuture<Fut: Future> {
future: Fut,
}

/// Errors that can occur when trying to spawn a [`ScopedFuture`].
#[derive(Error, Debug, Clone)]
pub enum ScopedFutureError {
#[error(
"Tried to spawn a scoped Future without a current reactive Owner."
)]
NoCurrentOwner,
}

impl<Fut: Future + 'static> Future for ScopedFuture<Fut> {
type Output = Option<Fut::Output>;

fn poll(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> Poll<Self::Output> {
// TODO: we need to think about how to make this
// not panic for scopes that have been cleaned up...
// or perhaps we can force the scope to not be cleaned
// up until all futures that have a handle to them are
// dropped...

let this = self.project();

if let Some(poll) = try_with_owner(*this.owner, || this.future.poll(cx))
Expand All @@ -1533,14 +1537,10 @@ impl<Fut: Future> ScopedFuture<Fut> {
/// # Panics
/// Panics if there is no current [`Owner`] context available.
#[track_caller]
pub fn new_current(fut: Fut) -> Self {
Self {
owner: Owner::current().expect(
"`ScopedFuture::new_current()` to be called within an `Owner` \
context",
),
future: fut,
}
pub fn new_current(fut: Fut) -> Result<Self, ScopedFutureError> {
Owner::current()
.map(|owner| Self { owner, future: fut })
.ok_or(ScopedFutureError::NoCurrentOwner)
}
}

Expand All @@ -1566,15 +1566,19 @@ pub fn spawn_local_with_owner(
/// # Panics
/// Panics if there is no [`Owner`] context available.
#[track_caller]
pub fn spawn_local_with_current_owner(fut: impl Future<Output = ()> + 'static) {
let scoped_future = ScopedFuture::new_current(fut);
pub fn spawn_local_with_current_owner(
fut: impl Future<Output = ()> + 'static,
) -> Result<(), ScopedFutureError> {
let scoped_future = ScopedFuture::new_current(fut)?;

crate::spawn_local(async move {
if scoped_future.await.is_none() {
// TODO: should we warn here?
// /* warning message */
}
});

Ok(())
}

/// Runs a future that has access to the provided [`Owner`]'s
Expand Down Expand Up @@ -1616,12 +1620,14 @@ pub fn try_spawn_local_with_owner(
pub fn try_spawn_local_with_current_owner(
fut: impl Future<Output = ()> + 'static,
on_cancelled: impl FnOnce() + 'static,
) {
let scoped_future = ScopedFuture::new_current(fut);
) -> Result<(), ScopedFutureError> {
let scoped_future = ScopedFuture::new_current(fut)?;

crate::spawn_local(async move {
if scoped_future.await.is_none() {
on_cancelled();
}
});

Ok(())
}

0 comments on commit 2b3c755

Please sign in to comment.