mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
lazy Future construction for AsyncDerived
This commit is contained in:
parent
d360cc280f
commit
961bf89a8b
2 changed files with 71 additions and 10 deletions
|
@ -12,7 +12,8 @@ use futures::Future;
|
|||
use hydration_context::SerializedDataId;
|
||||
use reactive_graph::{
|
||||
computed::{
|
||||
ArcAsyncDerived, ArcMemo, AsyncDerived, AsyncDerivedFuture, AsyncState,
|
||||
ArcAsyncDerived, ArcAsyncDerivedFuture, ArcMemo, AsyncDerived,
|
||||
AsyncDerivedFuture, AsyncState,
|
||||
},
|
||||
graph::{Source, ToAnySource, ToAnySubscriber},
|
||||
owner::Owner,
|
||||
|
@ -157,6 +158,7 @@ where
|
|||
T::SerErr: Debug,
|
||||
T::DeErr: Debug,
|
||||
{
|
||||
#[track_caller]
|
||||
pub fn new_with_encoding<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
|
@ -241,7 +243,7 @@ where
|
|||
T: Clone + 'static,
|
||||
{
|
||||
type Output = T;
|
||||
type IntoFuture = AsyncDerivedFuture<T>;
|
||||
type IntoFuture = ArcAsyncDerivedFuture<T>;
|
||||
|
||||
fn into_future(self) -> Self::IntoFuture {
|
||||
self.data.into_future()
|
||||
|
@ -281,6 +283,7 @@ where
|
|||
T::SerErr: Debug,
|
||||
T::DeErr: Debug,
|
||||
{
|
||||
#[track_caller]
|
||||
pub fn new<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
|
@ -300,6 +303,7 @@ where
|
|||
T::SerErr: Debug,
|
||||
T::DeErr: Debug,
|
||||
{
|
||||
#[track_caller]
|
||||
pub fn new_serde<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
|
@ -320,6 +324,7 @@ where
|
|||
T::SerErr: Debug,
|
||||
T::DeErr: Debug,
|
||||
{
|
||||
#[track_caller]
|
||||
pub fn new_serde_wb<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
|
@ -340,6 +345,7 @@ where
|
|||
T::SerErr: Debug,
|
||||
T::DeErr: Debug,
|
||||
{
|
||||
#[track_caller]
|
||||
pub fn new_miniserde<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
|
@ -360,6 +366,7 @@ where
|
|||
T::SerErr: Debug,
|
||||
T::DeErr: Debug,
|
||||
{
|
||||
#[track_caller]
|
||||
pub fn new_serde_lite<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
|
@ -380,6 +387,7 @@ where
|
|||
T::SerErr: Debug,
|
||||
T::DeErr: Debug,
|
||||
{
|
||||
#[track_caller]
|
||||
pub fn new_rkyv<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
|
@ -400,6 +408,7 @@ where
|
|||
T::SerErr: Debug,
|
||||
T::DeErr: Debug,
|
||||
{
|
||||
#[track_caller]
|
||||
pub fn new_with_encoding<S, Fut>(
|
||||
source: impl Fn() -> S + Send + Sync + 'static,
|
||||
fetcher: impl Fn(S) -> Fut + Send + Sync + 'static,
|
||||
|
@ -425,6 +434,7 @@ where
|
|||
type Output = T;
|
||||
type IntoFuture = AsyncDerivedFuture<T>;
|
||||
|
||||
#[track_caller]
|
||||
fn into_future(self) -> Self::IntoFuture {
|
||||
self.data.into_future()
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
use super::{ArcAsyncDerived, AsyncState};
|
||||
use super::{ArcAsyncDerived, AsyncDerived, AsyncState};
|
||||
use crate::{
|
||||
graph::{AnySource, ToAnySource},
|
||||
signal::guards::Plain,
|
||||
traits::Track,
|
||||
traits::{DefinedAt, Track},
|
||||
unwrap_signal,
|
||||
};
|
||||
use or_poisoned::OrPoisoned;
|
||||
use pin_project_lite::pin_project;
|
||||
use std::{
|
||||
future::{Future, IntoFuture},
|
||||
pin::Pin,
|
||||
|
@ -14,13 +16,13 @@ use std::{
|
|||
|
||||
/// A [`Future`] that is ready when an [`ArcAsyncDerived`] is finished loading or reloading,
|
||||
/// but does not contain its value.
|
||||
pub struct AsyncDerivedReadyFuture<T> {
|
||||
pub struct ArcAsyncDerivedReadyFuture<T> {
|
||||
pub(crate) source: AnySource,
|
||||
pub(crate) value: Arc<RwLock<AsyncState<T>>>,
|
||||
pub(crate) wakers: Arc<RwLock<Vec<Waker>>>,
|
||||
}
|
||||
|
||||
impl<T: 'static> Future for AsyncDerivedReadyFuture<T> {
|
||||
impl<T: 'static> Future for ArcAsyncDerivedReadyFuture<T> {
|
||||
type Output = ();
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
|
@ -38,7 +40,7 @@ impl<T: 'static> Future for AsyncDerivedReadyFuture<T> {
|
|||
|
||||
/// A [`Future`] that is ready when an [`ArcAsyncDerived`] is finished loading or reloading,
|
||||
/// and contains its value.
|
||||
pub struct AsyncDerivedFuture<T> {
|
||||
pub struct ArcAsyncDerivedFuture<T> {
|
||||
source: AnySource,
|
||||
value: Arc<RwLock<AsyncState<T>>>,
|
||||
wakers: Arc<RwLock<Vec<Waker>>>,
|
||||
|
@ -49,10 +51,10 @@ where
|
|||
T: Clone + 'static,
|
||||
{
|
||||
type Output = T;
|
||||
type IntoFuture = AsyncDerivedFuture<T>;
|
||||
type IntoFuture = ArcAsyncDerivedFuture<T>;
|
||||
|
||||
fn into_future(self) -> Self::IntoFuture {
|
||||
AsyncDerivedFuture {
|
||||
ArcAsyncDerivedFuture {
|
||||
source: self.to_any_source(),
|
||||
value: Arc::clone(&self.value),
|
||||
wakers: Arc::clone(&self.wakers),
|
||||
|
@ -62,7 +64,7 @@ where
|
|||
|
||||
// this is implemented to output T by cloning it because read guards should not be held across
|
||||
// .await points, and it's way too easy to trip up by doing that!
|
||||
impl<T> Future for AsyncDerivedFuture<T>
|
||||
impl<T> Future for ArcAsyncDerivedFuture<T>
|
||||
where
|
||||
T: Clone + 'static,
|
||||
{
|
||||
|
@ -82,3 +84,52 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin_project! {
|
||||
/// A [`Future`] that is ready when an [`AsyncDerived`] is finished loading or reloading,
|
||||
/// and contains its value.
|
||||
pub struct AsyncDerivedFuture<T> {
|
||||
this: AsyncDerived<T>,
|
||||
#[pin]
|
||||
inner: Option<ArcAsyncDerivedFuture<T>>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoFuture for AsyncDerived<T>
|
||||
where
|
||||
T: Send + Sync + Clone + 'static,
|
||||
{
|
||||
type Output = T;
|
||||
type IntoFuture = AsyncDerivedFuture<T>;
|
||||
|
||||
fn into_future(self) -> Self::IntoFuture {
|
||||
AsyncDerivedFuture {
|
||||
this: self,
|
||||
inner: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this is implemented to output T by cloning it because read guards should not be held across
|
||||
// .await points, and it's way too easy to trip up by doing that!
|
||||
impl<T> Future for AsyncDerivedFuture<T>
|
||||
where
|
||||
T: Send + Sync + Clone + 'static,
|
||||
{
|
||||
type Output = T;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let mut this = self.project();
|
||||
if this.inner.is_none() {
|
||||
let stored = *this.this;
|
||||
this.inner.set(Some(
|
||||
stored
|
||||
.inner
|
||||
.get()
|
||||
.unwrap_or_else(unwrap_signal!(stored))
|
||||
.into_future(),
|
||||
));
|
||||
}
|
||||
this.inner.as_pin_mut().unwrap().poll(cx)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue