mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
feat: add .by_ref()
to create a Future
from an AsyncDerived
(etc.) that takes a reference, rather than cloning
This commit is contained in:
parent
4e4deef144
commit
14b7073863
5 changed files with 124 additions and 27 deletions
|
@ -87,7 +87,6 @@ pub fn fetch_example() -> impl IntoView {
|
|||
<ul>
|
||||
{move || Suspend(async move {
|
||||
cats.await
|
||||
.as_ref()
|
||||
.map(|cats| {
|
||||
cats.iter()
|
||||
.map(|s| {
|
||||
|
@ -99,7 +98,6 @@ pub fn fetch_example() -> impl IntoView {
|
|||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.map_err(Clone::clone)
|
||||
})}
|
||||
|
||||
</ul>
|
||||
|
|
|
@ -121,7 +121,6 @@ pub fn Todos() -> impl IntoView {
|
|||
Suspend(async move {
|
||||
todos
|
||||
.await
|
||||
.as_ref()
|
||||
.map(|todos| {
|
||||
if todos.is_empty() {
|
||||
Either::Left(view! { <p>"No tasks were found."</p> })
|
||||
|
@ -145,7 +144,6 @@ pub fn Todos() -> impl IntoView {
|
|||
)
|
||||
}
|
||||
})
|
||||
.map_err(Clone::clone)
|
||||
})
|
||||
};
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@ use futures::Future;
|
|||
use hydration_context::SerializedDataId;
|
||||
use reactive_graph::{
|
||||
computed::{
|
||||
ArcAsyncDerived, ArcAsyncDerivedFuture, ArcMemo, AsyncDerived,
|
||||
AsyncDerivedFuture, AsyncDerivedGuard,
|
||||
ArcAsyncDerived, ArcAsyncDerivedFuture, ArcAsyncDerivedRefFuture,
|
||||
ArcMemo, AsyncDerived, AsyncDerivedFuture, AsyncDerivedRefFuture,
|
||||
},
|
||||
graph::{Source, ToAnySubscriber},
|
||||
owner::Owner,
|
||||
|
@ -244,7 +244,7 @@ impl<T, Ser> IntoFuture for ArcResource<T, Ser>
|
|||
where
|
||||
T: Clone + 'static,
|
||||
{
|
||||
type Output = AsyncDerivedGuard<T>;
|
||||
type Output = T;
|
||||
type IntoFuture = ArcAsyncDerivedFuture<T>;
|
||||
|
||||
fn into_future(self) -> Self::IntoFuture {
|
||||
|
@ -252,6 +252,15 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, Ser> ArcResource<T, Ser>
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
pub fn by_ref(&self) -> ArcAsyncDerivedRefFuture<T> {
|
||||
self.data.by_ref()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Resource<T, Ser>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
|
@ -433,7 +442,7 @@ impl<T, Ser> IntoFuture for Resource<T, Ser>
|
|||
where
|
||||
T: Clone + Send + Sync + 'static,
|
||||
{
|
||||
type Output = AsyncDerivedGuard<T>;
|
||||
type Output = T;
|
||||
type IntoFuture = AsyncDerivedFuture<T>;
|
||||
|
||||
#[track_caller]
|
||||
|
@ -441,3 +450,12 @@ where
|
|||
self.data.into_future()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Ser> Resource<T, Ser>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
{
|
||||
pub fn by_ref(&self) -> AsyncDerivedRefFuture<T> {
|
||||
self.data.by_ref()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ pub struct AsyncDerived<T> {
|
|||
pub(crate) inner: StoredValue<ArcAsyncDerived<T>>,
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> Dispose for AsyncDerived<T> {
|
||||
impl<T: 'static> Dispose for AsyncDerived<T> {
|
||||
fn dispose(self) {
|
||||
self.inner.dispose()
|
||||
}
|
||||
|
@ -105,15 +105,15 @@ impl<T: Send + Sync + 'static> AsyncDerived<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> Copy for AsyncDerived<T> {}
|
||||
impl<T> Copy for AsyncDerived<T> {}
|
||||
|
||||
impl<T: Send + Sync + 'static> Clone for AsyncDerived<T> {
|
||||
impl<T> Clone for AsyncDerived<T> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> Debug for AsyncDerived<T> {
|
||||
impl<T> Debug for AsyncDerived<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("AsyncDerived")
|
||||
.field("type", &std::any::type_name::<T>())
|
||||
|
@ -122,7 +122,7 @@ impl<T: Send + Sync + 'static> Debug for AsyncDerived<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> DefinedAt for AsyncDerived<T> {
|
||||
impl<T> DefinedAt for AsyncDerived<T> {
|
||||
#[inline(always)]
|
||||
fn defined_at(&self) -> Option<&'static Location<'static>> {
|
||||
#[cfg(debug_assertions)]
|
||||
|
|
|
@ -47,20 +47,11 @@ impl Future for ArcAsyncDerivedReadyFuture {
|
|||
}
|
||||
}
|
||||
|
||||
/// A [`Future`] that is ready when an [`ArcAsyncDerived`] is finished loading or reloading,
|
||||
/// and contains its value.
|
||||
pub struct ArcAsyncDerivedFuture<T> {
|
||||
source: AnySource,
|
||||
value: Arc<async_lock::RwLock<Option<T>>>,
|
||||
loading: Arc<AtomicBool>,
|
||||
wakers: Arc<RwLock<Vec<Waker>>>,
|
||||
}
|
||||
|
||||
impl<T> IntoFuture for ArcAsyncDerived<T>
|
||||
where
|
||||
T: Clone + 'static,
|
||||
{
|
||||
type Output = AsyncDerivedGuard<T>;
|
||||
type Output = T;
|
||||
type IntoFuture = ArcAsyncDerivedFuture<T>;
|
||||
|
||||
fn into_future(self) -> Self::IntoFuture {
|
||||
|
@ -73,11 +64,62 @@ 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!
|
||||
/// A [`Future`] that is ready when an [`ArcAsyncDerived`] is finished loading or reloading,
|
||||
/// and contains its value. `.await`ing this clones the value `T`.
|
||||
pub struct ArcAsyncDerivedFuture<T> {
|
||||
source: AnySource,
|
||||
value: Arc<async_lock::RwLock<Option<T>>>,
|
||||
loading: Arc<AtomicBool>,
|
||||
wakers: Arc<RwLock<Vec<Waker>>>,
|
||||
}
|
||||
|
||||
impl<T> Future for ArcAsyncDerivedFuture<T>
|
||||
where
|
||||
T: Clone + 'static,
|
||||
{
|
||||
type Output = T;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let waker = cx.waker();
|
||||
self.source.track();
|
||||
let value = self.value.read_arc();
|
||||
pin_mut!(value);
|
||||
match (self.loading.load(Ordering::Relaxed), value.poll(cx)) {
|
||||
(true, _) => {
|
||||
self.wakers.write().or_poisoned().push(waker.clone());
|
||||
Poll::Pending
|
||||
}
|
||||
(_, Poll::Pending) => Poll::Pending,
|
||||
(_, Poll::Ready(guard)) => {
|
||||
Poll::Ready(guard.as_ref().unwrap().clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> ArcAsyncDerived<T> {
|
||||
pub fn by_ref(&self) -> ArcAsyncDerivedRefFuture<T> {
|
||||
ArcAsyncDerivedRefFuture {
|
||||
source: self.to_any_source(),
|
||||
value: Arc::clone(&self.value),
|
||||
loading: Arc::clone(&self.loading),
|
||||
wakers: Arc::clone(&self.wakers),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Future`] that is ready when an [`ArcAsyncDerived`] is finished loading or reloading,
|
||||
/// and yields an [`AsyncDerivedGuard`] that dereferences to its value.
|
||||
pub struct ArcAsyncDerivedRefFuture<T> {
|
||||
source: AnySource,
|
||||
value: Arc<async_lock::RwLock<Option<T>>>,
|
||||
loading: Arc<AtomicBool>,
|
||||
wakers: Arc<RwLock<Vec<Waker>>>,
|
||||
}
|
||||
|
||||
impl<T> Future for ArcAsyncDerivedRefFuture<T>
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
type Output = AsyncDerivedGuard<T>;
|
||||
|
||||
|
@ -115,7 +157,7 @@ impl<T> IntoFuture for AsyncDerived<T>
|
|||
where
|
||||
T: Send + Sync + Clone + 'static,
|
||||
{
|
||||
type Output = AsyncDerivedGuard<T>;
|
||||
type Output = T;
|
||||
type IntoFuture = AsyncDerivedFuture<T>;
|
||||
|
||||
fn into_future(self) -> Self::IntoFuture {
|
||||
|
@ -130,7 +172,7 @@ impl<T> Future for AsyncDerivedFuture<T>
|
|||
where
|
||||
T: Send + Sync + Clone + 'static,
|
||||
{
|
||||
type Output = AsyncDerivedGuard<T>;
|
||||
type Output = T;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let mut this = self.project();
|
||||
|
@ -147,3 +189,44 @@ where
|
|||
this.inner.as_pin_mut().unwrap().poll(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> AsyncDerived<T> {
|
||||
pub fn by_ref(&self) -> AsyncDerivedRefFuture<T> {
|
||||
AsyncDerivedRefFuture {
|
||||
this: *self,
|
||||
inner: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pin_project! {
|
||||
/// A [`Future`] that is ready when an [`AsyncDerived`] is finished loading or reloading,
|
||||
/// and contains its value.
|
||||
pub struct AsyncDerivedRefFuture<T> {
|
||||
this: AsyncDerived<T>,
|
||||
#[pin]
|
||||
inner: Option<ArcAsyncDerivedRefFuture<T>>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Future for AsyncDerivedRefFuture<T>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
{
|
||||
type Output = AsyncDerivedGuard<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))
|
||||
.by_ref(),
|
||||
));
|
||||
}
|
||||
this.inner.as_pin_mut().unwrap().poll(cx)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue