mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
make guard types more nestable/flexible so that we can implement render traits on any of them
This commit is contained in:
parent
44a0a0a93a
commit
4df42cbc60
22 changed files with 251 additions and 183 deletions
|
@ -30,7 +30,7 @@ pub fn async_example() -> impl IntoView {
|
|||
|
||||
let times = move || {
|
||||
trigger.track();
|
||||
async move { (a2.await.to_string(), "test") } //{ (a2.await.to_string(), " and ", b2.await.to_string()) }
|
||||
async move { (b2.await, a2.await, " and ") }
|
||||
.suspend()
|
||||
.with_fallback("Loading...")
|
||||
.track()
|
||||
|
|
|
@ -16,6 +16,7 @@ guardian = "1"
|
|||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1", features = ["rt-multi-thread", "time", "macros"] }
|
||||
any_spawner = { workspace = true, features = ["tokio"] }
|
||||
|
||||
[features]
|
||||
nightly = []
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
AnySource, AnySubscriber, ReactiveNode, Source, Subscriber,
|
||||
ToAnySource, ToAnySubscriber,
|
||||
},
|
||||
signal::MappedSignalReadGuard,
|
||||
signal::guards::{Mapped, Plain, ReadGuard},
|
||||
traits::{DefinedAt, ReadUntracked},
|
||||
};
|
||||
use core::fmt::Debug;
|
||||
|
@ -159,15 +159,16 @@ impl<T: Send + Sync + 'static> Subscriber for ArcMemo<T> {
|
|||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> ReadUntracked for ArcMemo<T> {
|
||||
type Value = MappedSignalReadGuard<MemoInner<T>, T>;
|
||||
type Value = ReadGuard<T, Mapped<Plain<MemoInner<T>>, T>>;
|
||||
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
self.update_if_necessary();
|
||||
|
||||
MappedSignalReadGuard::try_new(Arc::clone(&self.inner), |t| {
|
||||
Mapped::try_new(Arc::clone(&self.inner), |t| {
|
||||
// safe to unwrap here because update_if_necessary
|
||||
// guarantees the value is Some
|
||||
t.value.as_ref().unwrap()
|
||||
})
|
||||
.map(ReadGuard::new)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
|||
SubscriberSet, ToAnySource, ToAnySubscriber,
|
||||
},
|
||||
owner::Owner,
|
||||
signal::SignalReadGuard,
|
||||
signal::guards::{Plain, ReadGuard},
|
||||
traits::{DefinedAt, ReadUntracked},
|
||||
};
|
||||
use any_spawner::Executor;
|
||||
|
@ -222,10 +222,10 @@ impl<T: 'static> ArcAsyncDerived<T> {
|
|||
}
|
||||
|
||||
impl<T: 'static> ReadUntracked for ArcAsyncDerived<T> {
|
||||
type Value = SignalReadGuard<AsyncState<T>>;
|
||||
type Value = ReadGuard<AsyncState<T>, Plain<AsyncState<T>>>;
|
||||
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
SignalReadGuard::try_new(Arc::clone(&self.value))
|
||||
Plain::try_new(Arc::clone(&self.value)).map(ReadGuard::new)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
ToAnySource, ToAnySubscriber,
|
||||
},
|
||||
owner::{Stored, StoredData},
|
||||
signal::{MappedSignalReadGuard, SignalReadGuard},
|
||||
signal::guards::{Mapped, Plain, ReadGuard},
|
||||
traits::{DefinedAt, ReadUntracked},
|
||||
unwrap_signal,
|
||||
};
|
||||
|
@ -136,7 +136,7 @@ impl<T: Send + Sync + 'static> DefinedAt for AsyncDerived<T> {
|
|||
}
|
||||
|
||||
impl<T: Send + Sync + Clone + 'static> IntoFuture for AsyncDerived<T> {
|
||||
type Output = MappedSignalReadGuard<AsyncState<T>, T>;
|
||||
type Output = ReadGuard<T, Mapped<Plain<AsyncState<T>>, T>>;
|
||||
type IntoFuture = AsyncDerivedFuture<T>;
|
||||
|
||||
#[track_caller]
|
||||
|
@ -147,7 +147,7 @@ impl<T: Send + Sync + Clone + 'static> IntoFuture for AsyncDerived<T> {
|
|||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> ReadUntracked for AsyncDerived<T> {
|
||||
type Value = SignalReadGuard<AsyncState<T>>;
|
||||
type Value = ReadGuard<AsyncState<T>, Plain<AsyncState<T>>>;
|
||||
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
self.get_value().map(|inner| inner.read_untracked())
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::{ArcAsyncDerived, AsyncState};
|
||||
use crate::{
|
||||
graph::{AnySource, ToAnySource},
|
||||
signal::{MappedSignalReadGuard, SignalReadGuard},
|
||||
signal::guards::{Mapped, Plain, ReadGuard},
|
||||
traits::Track,
|
||||
};
|
||||
use or_poisoned::OrPoisoned;
|
||||
|
@ -45,7 +45,7 @@ pub struct AsyncDerivedFuture<T> {
|
|||
}
|
||||
|
||||
impl<T: 'static> IntoFuture for ArcAsyncDerived<T> {
|
||||
type Output = MappedSignalReadGuard<AsyncState<T>, T>;
|
||||
type Output = ReadGuard<T, Mapped<Plain<AsyncState<T>>, T>>;
|
||||
type IntoFuture = AsyncDerivedFuture<T>;
|
||||
|
||||
fn into_future(self) -> Self::IntoFuture {
|
||||
|
@ -58,29 +58,27 @@ impl<T: 'static> IntoFuture for ArcAsyncDerived<T> {
|
|||
}
|
||||
|
||||
impl<T: 'static> Future for AsyncDerivedFuture<T> {
|
||||
type Output = MappedSignalReadGuard<AsyncState<T>, T>;
|
||||
type Output = ReadGuard<T, Mapped<Plain<AsyncState<T>>, T>>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let waker = cx.waker();
|
||||
self.source.track();
|
||||
let value = SignalReadGuard::try_new(Arc::clone(&self.value))
|
||||
.expect("lock poisoned");
|
||||
let value =
|
||||
Plain::try_new(Arc::clone(&self.value)).expect("lock poisoned");
|
||||
match &*value {
|
||||
AsyncState::Loading | AsyncState::Reloading(_) => {
|
||||
self.wakers.write().or_poisoned().push(waker.clone());
|
||||
Poll::Pending
|
||||
}
|
||||
AsyncState::Complete(_) => Poll::Ready(
|
||||
MappedSignalReadGuard::try_new(
|
||||
Arc::clone(&self.value),
|
||||
|inner| match inner {
|
||||
AsyncState::Complete(_) => {
|
||||
Poll::Ready(ReadGuard::new(Mapped::new(value, |inner| {
|
||||
match inner {
|
||||
AsyncState::Complete(value) => value,
|
||||
// we've just checked this value is Complete
|
||||
_ => unreachable!(),
|
||||
},
|
||||
)
|
||||
.expect("lock poisoned"),
|
||||
),
|
||||
}
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,10 @@ use crate::{
|
|||
owner::Owner,
|
||||
};
|
||||
use or_poisoned::OrPoisoned;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
pub struct MemoInner<T> {
|
||||
pub(crate) value: Option<T>,
|
||||
|
@ -20,6 +23,12 @@ pub struct MemoInner<T> {
|
|||
pub(crate) any_subscriber: AnySubscriber,
|
||||
}
|
||||
|
||||
impl<T> Debug for MemoInner<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("MemoInner").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> MemoInner<T> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn new(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::{inner::MemoInner, ArcMemo};
|
||||
use crate::{
|
||||
owner::{Stored, StoredData},
|
||||
signal::MappedSignalReadGuard,
|
||||
signal::guards::{Mapped, Plain, ReadGuard},
|
||||
traits::{DefinedAt, ReadUntracked, Track},
|
||||
};
|
||||
use std::{fmt::Debug, panic::Location};
|
||||
|
@ -81,7 +81,7 @@ impl<T: Send + Sync + 'static> Track for Memo<T> {
|
|||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> ReadUntracked for Memo<T> {
|
||||
type Value = MappedSignalReadGuard<MemoInner<T>, T>;
|
||||
type Value = ReadGuard<T, Mapped<Plain<MemoInner<T>>, T>>;
|
||||
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
self.get_value().map(|inner| inner.read_untracked())
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
pub struct SignalReadGuard<'a>(RwLockReadGuard<'a>);
|
|
@ -16,7 +16,7 @@
|
|||
//! use reactive_graph::{
|
||||
//! computed::ArcMemo,
|
||||
//! effect::Effect,
|
||||
//! prelude::{Readable, Set},
|
||||
//! prelude::{Read, Set},
|
||||
//! signal::ArcRwSignal,
|
||||
//! };
|
||||
//!
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
mod arc_read;
|
||||
mod arc_rw;
|
||||
mod arc_write;
|
||||
mod guards;
|
||||
pub mod guards;
|
||||
mod read;
|
||||
mod rw;
|
||||
mod subscriber_traits;
|
||||
|
@ -10,7 +10,6 @@ mod write;
|
|||
pub use arc_read::*;
|
||||
pub use arc_rw::*;
|
||||
pub use arc_write::*;
|
||||
pub use guards::*;
|
||||
pub use read::*;
|
||||
pub use rw::*;
|
||||
pub use write::*;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use super::{subscriber_traits::AsSubscriberSet, SignalReadGuard};
|
||||
use super::{
|
||||
guards::{Plain, ReadGuard},
|
||||
subscriber_traits::AsSubscriberSet,
|
||||
};
|
||||
use crate::{
|
||||
graph::SubscriberSet,
|
||||
traits::{DefinedAt, IsDisposed, ReadUntracked},
|
||||
|
@ -83,10 +86,10 @@ impl<T> AsSubscriberSet for ArcReadSignal<T> {
|
|||
}
|
||||
|
||||
impl<T: 'static> ReadUntracked for ArcReadSignal<T> {
|
||||
type Value = SignalReadGuard<T>;
|
||||
type Value = ReadGuard<T, Plain<T>>;
|
||||
|
||||
#[track_caller]
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
SignalReadGuard::try_new(Arc::clone(&self.value))
|
||||
Plain::try_new(Arc::clone(&self.value)).map(ReadGuard::new)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::{
|
||||
subscriber_traits::AsSubscriberSet, ArcReadSignal, ArcWriteSignal,
|
||||
SignalReadGuard, SignalUntrackedWriteGuard, SignalWriteGuard,
|
||||
guards::{Plain, ReadGuard, UntrackedWriteGuard, WriteGuard},
|
||||
subscriber_traits::AsSubscriberSet,
|
||||
ArcReadSignal, ArcWriteSignal,
|
||||
};
|
||||
use crate::{
|
||||
graph::{ReactiveNode, SubscriberSet},
|
||||
|
@ -113,10 +114,10 @@ impl<T> AsSubscriberSet for ArcRwSignal<T> {
|
|||
}
|
||||
|
||||
impl<T: 'static> ReadUntracked for ArcRwSignal<T> {
|
||||
type Value = SignalReadGuard<T>;
|
||||
type Value = ReadGuard<T, Plain<T>>;
|
||||
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
SignalReadGuard::try_new(Arc::clone(&self.value))
|
||||
Plain::try_new(Arc::clone(&self.value)).map(ReadGuard::new)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,16 +130,16 @@ impl<T> Trigger for ArcRwSignal<T> {
|
|||
impl<T> Writeable for ArcRwSignal<T> {
|
||||
type Value = T;
|
||||
|
||||
fn try_write(&self) -> Option<SignalWriteGuard<'_, Self, Self::Value>> {
|
||||
fn try_write(&self) -> Option<WriteGuard<'_, Self, Self::Value>> {
|
||||
self.value
|
||||
.write()
|
||||
.ok()
|
||||
.map(|guard| SignalWriteGuard::new(self, guard))
|
||||
.map(|guard| WriteGuard::new(self, guard))
|
||||
}
|
||||
|
||||
fn try_write_untracked(
|
||||
&self,
|
||||
) -> Option<SignalUntrackedWriteGuard<'_, Self::Value>> {
|
||||
self.value.write().ok().map(SignalUntrackedWriteGuard::from)
|
||||
) -> Option<UntrackedWriteGuard<'_, Self::Value>> {
|
||||
self.value.write().ok().map(UntrackedWriteGuard::from)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::{SignalUntrackedWriteGuard, SignalWriteGuard};
|
||||
use super::guards::{UntrackedWriteGuard, WriteGuard};
|
||||
use crate::{
|
||||
graph::{ReactiveNode, SubscriberSet},
|
||||
prelude::{IsDisposed, Trigger},
|
||||
|
@ -83,16 +83,16 @@ impl<T> Trigger for ArcWriteSignal<T> {
|
|||
impl<T> Writeable for ArcWriteSignal<T> {
|
||||
type Value = T;
|
||||
|
||||
fn try_write(&self) -> Option<SignalWriteGuard<'_, Self, Self::Value>> {
|
||||
fn try_write(&self) -> Option<WriteGuard<'_, Self, Self::Value>> {
|
||||
self.value
|
||||
.write()
|
||||
.ok()
|
||||
.map(|guard| SignalWriteGuard::new(self, guard))
|
||||
.map(|guard| WriteGuard::new(self, guard))
|
||||
}
|
||||
|
||||
fn try_write_untracked(
|
||||
&self,
|
||||
) -> Option<SignalUntrackedWriteGuard<'_, Self::Value>> {
|
||||
self.value.write().ok().map(SignalUntrackedWriteGuard::from)
|
||||
) -> Option<UntrackedWriteGuard<'_, Self::Value>> {
|
||||
self.value.write().ok().map(UntrackedWriteGuard::from)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,29 +3,76 @@ use core::fmt::Debug;
|
|||
use guardian::ArcRwLockReadGuardian;
|
||||
use std::{
|
||||
fmt::Display,
|
||||
marker::PhantomData,
|
||||
ops::{Deref, DerefMut},
|
||||
sync::{Arc, RwLock, RwLockWriteGuard},
|
||||
};
|
||||
|
||||
pub struct SignalReadGuard<T: 'static> {
|
||||
#[derive(Debug)]
|
||||
pub struct ReadGuard<T, Inner> {
|
||||
ty: PhantomData<T>,
|
||||
inner: Inner,
|
||||
}
|
||||
|
||||
impl<T, Inner> ReadGuard<T, Inner> {
|
||||
pub fn new(inner: Inner) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
ty: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Inner> Deref for ReadGuard<T, Inner>
|
||||
where
|
||||
Inner: Deref<Target = T>,
|
||||
{
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.inner.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Inner> PartialEq<T> for ReadGuard<T, Inner>
|
||||
where
|
||||
Inner: Deref<Target = T>,
|
||||
T: PartialEq,
|
||||
{
|
||||
fn eq(&self, other: &Inner::Target) -> bool {
|
||||
self.deref() == other
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Inner> Display for ReadGuard<T, Inner>
|
||||
where
|
||||
Inner: Deref<Target = T>,
|
||||
T: Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
Display::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Plain<T: 'static> {
|
||||
guard: ArcRwLockReadGuardian<T>,
|
||||
}
|
||||
|
||||
impl<T: 'static> Debug for SignalReadGuard<T> {
|
||||
impl<T: 'static> Debug for Plain<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("SignalReadGuard").finish()
|
||||
f.debug_struct("Plain").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> SignalReadGuard<T> {
|
||||
pub fn try_new(inner: Arc<RwLock<T>>) -> Option<Self> {
|
||||
impl<T: 'static> Plain<T> {
|
||||
pub(crate) fn try_new(inner: Arc<RwLock<T>>) -> Option<Self> {
|
||||
ArcRwLockReadGuardian::take(inner)
|
||||
.ok()
|
||||
.map(|guard| SignalReadGuard { guard })
|
||||
.map(|guard| Plain { guard })
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for SignalReadGuard<T> {
|
||||
impl<T> Deref for Plain<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
@ -33,74 +80,92 @@ impl<T> Deref for SignalReadGuard<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq> PartialEq for SignalReadGuard<T> {
|
||||
impl<T: PartialEq> PartialEq for Plain<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
**self == **other
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq> PartialEq<T> for SignalReadGuard<T> {
|
||||
impl<T: PartialEq> PartialEq<T> for Plain<T> {
|
||||
fn eq(&self, other: &T) -> bool {
|
||||
**self == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Display> Display for SignalReadGuard<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
Display::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MappedSignalReadGuard<T: 'static, U> {
|
||||
guard: ArcRwLockReadGuardian<T>,
|
||||
map_fn: fn(&T) -> &U,
|
||||
}
|
||||
|
||||
impl<T: 'static, U> Debug for MappedSignalReadGuard<T, U> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("MappedSignalReadGuard").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static, U> MappedSignalReadGuard<T, U> {
|
||||
pub fn try_new(
|
||||
inner: Arc<RwLock<T>>,
|
||||
map_fn: fn(&T) -> &U,
|
||||
) -> Option<Self> {
|
||||
ArcRwLockReadGuardian::take(inner)
|
||||
.ok()
|
||||
.map(|guard| MappedSignalReadGuard { guard, map_fn })
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Deref for MappedSignalReadGuard<T, U> {
|
||||
type Target = U;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
(self.map_fn)(self.guard.deref())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U: PartialEq> PartialEq for MappedSignalReadGuard<T, U> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
**self == **other
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U: PartialEq> PartialEq<U> for MappedSignalReadGuard<T, U> {
|
||||
fn eq(&self, other: &U) -> bool {
|
||||
**self == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U: Display> Display for MappedSignalReadGuard<T, U> {
|
||||
impl<T: Display> Display for Plain<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
Display::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SignalWriteGuard<'a, S, T>
|
||||
pub struct Mapped<Inner, U>
|
||||
where
|
||||
Inner: Deref,
|
||||
{
|
||||
inner: Inner,
|
||||
map_fn: fn(&Inner::Target) -> &U,
|
||||
}
|
||||
|
||||
impl<Inner, U> Mapped<Inner, U>
|
||||
where
|
||||
Inner: Deref,
|
||||
{
|
||||
pub(crate) fn new(inner: Inner, map_fn: fn(&Inner::Target) -> &U) -> Self {
|
||||
Self { inner, map_fn }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static, U> Mapped<Plain<T>, U> {
|
||||
pub(crate) fn try_new(
|
||||
inner: Arc<RwLock<T>>,
|
||||
map_fn: fn(&T) -> &U,
|
||||
) -> Option<Self> {
|
||||
let inner = Plain::try_new(inner)?;
|
||||
Some(Self { inner, map_fn })
|
||||
}
|
||||
}
|
||||
|
||||
impl<Inner, U> Deref for Mapped<Inner, U>
|
||||
where
|
||||
Inner: Deref,
|
||||
{
|
||||
type Target = U;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
(self.map_fn)(self.inner.deref())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Inner, U: PartialEq> PartialEq for Mapped<Inner, U>
|
||||
where
|
||||
Inner: Deref,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
**self == **other
|
||||
}
|
||||
}
|
||||
|
||||
impl<Inner, U: PartialEq> PartialEq<U> for Mapped<Inner, U>
|
||||
where
|
||||
Inner: Deref,
|
||||
{
|
||||
fn eq(&self, other: &U) -> bool {
|
||||
**self == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl<Inner, U: Display> Display for Mapped<Inner, U>
|
||||
where
|
||||
Inner: Deref,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
Display::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WriteGuard<'a, S, T>
|
||||
where
|
||||
S: Trigger,
|
||||
{
|
||||
|
@ -108,7 +173,7 @@ where
|
|||
guard: Option<RwLockWriteGuard<'a, T>>,
|
||||
}
|
||||
|
||||
impl<'a, S, T> SignalWriteGuard<'a, S, T>
|
||||
impl<'a, S, T> WriteGuard<'a, S, T>
|
||||
where
|
||||
S: Trigger,
|
||||
{
|
||||
|
@ -120,7 +185,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, S, T> Deref for SignalWriteGuard<'a, S, T>
|
||||
impl<'a, S, T> Deref for WriteGuard<'a, S, T>
|
||||
where
|
||||
S: Trigger,
|
||||
{
|
||||
|
@ -137,7 +202,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, S, T> DerefMut for SignalWriteGuard<'a, S, T>
|
||||
impl<'a, S, T> DerefMut for WriteGuard<'a, S, T>
|
||||
where
|
||||
S: Trigger,
|
||||
{
|
||||
|
@ -153,15 +218,15 @@ where
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SignalUntrackedWriteGuard<'a, T>(RwLockWriteGuard<'a, T>);
|
||||
pub struct UntrackedWriteGuard<'a, T>(RwLockWriteGuard<'a, T>);
|
||||
|
||||
impl<'a, T> From<RwLockWriteGuard<'a, T>> for SignalUntrackedWriteGuard<'a, T> {
|
||||
impl<'a, T> From<RwLockWriteGuard<'a, T>> for UntrackedWriteGuard<'a, T> {
|
||||
fn from(value: RwLockWriteGuard<'a, T>) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Deref for SignalUntrackedWriteGuard<'a, T> {
|
||||
impl<'a, T> Deref for UntrackedWriteGuard<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
@ -169,14 +234,14 @@ impl<'a, T> Deref for SignalUntrackedWriteGuard<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T> DerefMut for SignalUntrackedWriteGuard<'a, T> {
|
||||
impl<'a, T> DerefMut for UntrackedWriteGuard<'a, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.0.deref_mut()
|
||||
}
|
||||
}
|
||||
|
||||
// Dropping the write guard will notify dependencies.
|
||||
impl<'a, S, T> Drop for SignalWriteGuard<'a, S, T>
|
||||
impl<'a, S, T> Drop for WriteGuard<'a, S, T>
|
||||
where
|
||||
S: Trigger,
|
||||
{
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use super::{
|
||||
subscriber_traits::AsSubscriberSet, ArcReadSignal, SignalReadGuard,
|
||||
guards::{Plain, ReadGuard},
|
||||
subscriber_traits::AsSubscriberSet,
|
||||
ArcReadSignal,
|
||||
};
|
||||
use crate::{
|
||||
graph::SubscriberSet,
|
||||
|
@ -78,7 +80,7 @@ impl<T: Send + Sync + 'static> AsSubscriberSet for ReadSignal<T> {
|
|||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> ReadUntracked for ReadSignal<T> {
|
||||
type Value = SignalReadGuard<T>;
|
||||
type Value = ReadGuard<T, Plain<T>>;
|
||||
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
self.get_value().map(|inner| inner.read_untracked())
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::{
|
||||
subscriber_traits::AsSubscriberSet, ArcRwSignal, ReadSignal,
|
||||
SignalReadGuard, WriteSignal,
|
||||
guards::{Plain, ReadGuard},
|
||||
subscriber_traits::AsSubscriberSet,
|
||||
ArcRwSignal, ReadSignal, WriteSignal,
|
||||
};
|
||||
use crate::{
|
||||
graph::{ReactiveNode, SubscriberSet},
|
||||
|
@ -147,7 +148,7 @@ impl<T: Send + Sync + 'static> AsSubscriberSet for RwSignal<T> {
|
|||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> ReadUntracked for RwSignal<T> {
|
||||
type Value = SignalReadGuard<T>;
|
||||
type Value = ReadGuard<T, Plain<T>>;
|
||||
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
self.get_value().map(|inner| inner.read_untracked())
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
|
||||
use crate::{
|
||||
graph::{Observer, Source, Subscriber, ToAnySource},
|
||||
signal::{SignalUntrackedWriteGuard, SignalWriteGuard},
|
||||
signal::guards::{UntrackedWriteGuard, WriteGuard},
|
||||
};
|
||||
use std::{ops::Deref, panic::Location};
|
||||
|
||||
|
@ -138,17 +138,17 @@ where
|
|||
pub trait Writeable: Sized + DefinedAt + Trigger {
|
||||
type Value: Sized;
|
||||
|
||||
fn try_write(&self) -> Option<SignalWriteGuard<'_, Self, Self::Value>>;
|
||||
fn try_write(&self) -> Option<WriteGuard<'_, Self, Self::Value>>;
|
||||
|
||||
fn try_write_untracked(
|
||||
&self,
|
||||
) -> Option<SignalUntrackedWriteGuard<'_, Self::Value>>;
|
||||
) -> Option<UntrackedWriteGuard<'_, Self::Value>>;
|
||||
|
||||
fn write(&self) -> SignalWriteGuard<'_, Self, Self::Value> {
|
||||
fn write(&self) -> WriteGuard<'_, Self, Self::Value> {
|
||||
self.try_write().unwrap_or_else(unwrap_signal!(self))
|
||||
}
|
||||
|
||||
fn write_untracked(&self) -> SignalUntrackedWriteGuard<'_, Self::Value> {
|
||||
fn write_untracked(&self) -> UntrackedWriteGuard<'_, Self::Value> {
|
||||
self.try_write_untracked()
|
||||
.unwrap_or_else(unwrap_signal!(self))
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ use reactive_graph::{
|
|||
traits::{Get, Read, Set, With, WithUntracked},
|
||||
};
|
||||
|
||||
#[cfg(feature = "tokio")]
|
||||
#[tokio::test]
|
||||
async fn arc_async_derived_calculates_eagerly() {
|
||||
use std::time::Duration;
|
||||
|
@ -22,7 +21,6 @@ async fn arc_async_derived_calculates_eagerly() {
|
|||
std::mem::forget(value);
|
||||
}
|
||||
|
||||
#[cfg(feature = "tokio")]
|
||||
#[tokio::test]
|
||||
async fn arc_async_derived_tracks_signal_change() {
|
||||
use std::time::Duration;
|
||||
|
@ -46,7 +44,6 @@ async fn arc_async_derived_tracks_signal_change() {
|
|||
std::mem::forget(value);
|
||||
}
|
||||
|
||||
#[cfg(feature = "tokio")]
|
||||
#[tokio::test]
|
||||
async fn async_derived_calculates_eagerly() {
|
||||
use std::time::Duration;
|
||||
|
@ -62,7 +59,6 @@ async fn async_derived_calculates_eagerly() {
|
|||
assert_eq!(*value.await, 42);
|
||||
}
|
||||
|
||||
#[cfg(feature = "tokio")]
|
||||
#[tokio::test]
|
||||
async fn async_derived_tracks_signal_change() {
|
||||
use std::time::Duration;
|
||||
|
@ -85,8 +81,10 @@ async fn async_derived_tracks_signal_change() {
|
|||
assert_eq!(value.await, 50);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_signal_traits_on_arc() {
|
||||
#[tokio::test]
|
||||
async fn read_signal_traits_on_arc() {
|
||||
_ = Executor::init_tokio();
|
||||
|
||||
let value = ArcAsyncDerived::new(move || async {});
|
||||
assert_eq!(value.read(), AsyncState::Loading);
|
||||
assert_eq!(value.with_untracked(|n| *n), AsyncState::Loading);
|
||||
|
@ -94,8 +92,10 @@ fn read_signal_traits_on_arc() {
|
|||
assert_eq!(value.get(), AsyncState::Loading);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_signal_traits_on_arena() {
|
||||
#[tokio::test]
|
||||
async fn read_signal_traits_on_arena() {
|
||||
_ = Executor::init_tokio();
|
||||
|
||||
let value = AsyncDerived::new(move || async {});
|
||||
println!("{:?}", value.read());
|
||||
assert_eq!(value.read(), AsyncState::Loading);
|
||||
|
|
|
@ -13,10 +13,9 @@ pub async fn tick() {
|
|||
tokio::time::sleep(std::time::Duration::from_micros(1)).await;
|
||||
}
|
||||
|
||||
#[cfg(feature = "futures-executor")]
|
||||
#[test]
|
||||
fn render_effect_runs() {
|
||||
_ = Executor::init_futures_executor();
|
||||
#[tokio::test]
|
||||
async fn render_effect_runs() {
|
||||
_ = Executor::init_tokio();
|
||||
|
||||
Executor::spawn(async {
|
||||
let a = RwSignal::new(-1);
|
||||
|
@ -45,10 +44,9 @@ fn render_effect_runs() {
|
|||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "futures-executor")]
|
||||
#[test]
|
||||
fn effect_runs() {
|
||||
_ = Executor::init_futures_executor();
|
||||
#[tokio::test]
|
||||
async fn effect_runs() {
|
||||
_ = Executor::init_tokio();
|
||||
|
||||
Executor::spawn(async {
|
||||
let a = RwSignal::new(-1);
|
||||
|
@ -74,10 +72,10 @@ fn effect_runs() {
|
|||
assert_eq!(b.read().unwrap().as_str(), "Value is 1");
|
||||
});
|
||||
}
|
||||
#[cfg(feature = "futures-executor")]
|
||||
#[test]
|
||||
fn dynamic_dependencies() {
|
||||
_ = Executor::init_futures_executor();
|
||||
|
||||
#[tokio::test]
|
||||
async fn dynamic_dependencies() {
|
||||
_ = Executor::init_tokio();
|
||||
|
||||
Executor::spawn(async {
|
||||
let first = RwSignal::new("Greg");
|
||||
|
@ -137,20 +135,3 @@ fn dynamic_dependencies() {
|
|||
assert_eq!(*combined_count.read().unwrap(), 5);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
#[cfg(feature = "futures-executor")]
|
||||
#[test]
|
||||
fn effect_runs() {
|
||||
_ = Executor::init_futures_executor();
|
||||
|
||||
Executor::spawn(async {});
|
||||
}
|
||||
|
||||
#[cfg(feature = "futures-executor")]
|
||||
#[test]
|
||||
fn effect_runs() {
|
||||
_ = Executor::init_futures_executor();
|
||||
|
||||
Executor::spawn(async {});
|
||||
}*/
|
||||
|
|
|
@ -169,10 +169,9 @@ fn diamond_problem() {
|
|||
assert_eq!(*combined_count.read().unwrap(), 1);
|
||||
}
|
||||
|
||||
#[cfg(feature = "tokio")]
|
||||
#[tokio::test]
|
||||
async fn dynamic_dependencies() {
|
||||
_ = Executor::init_futures_executor();
|
||||
_ = Executor::init_tokio();
|
||||
|
||||
let first = RwSignal::new("Greg");
|
||||
let last = RwSignal::new("Johnston");
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
|||
PositionState, Render, ToTemplate,
|
||||
},
|
||||
};
|
||||
use reactive_graph::signal::SignalReadGuard;
|
||||
use reactive_graph::signal::guards::ReadGuard;
|
||||
use std::{
|
||||
fmt::Write,
|
||||
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
|
||||
|
@ -18,6 +18,7 @@ use std::{
|
|||
NonZeroIsize, NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64,
|
||||
NonZeroU8, NonZeroUsize,
|
||||
},
|
||||
ops::Deref,
|
||||
};
|
||||
|
||||
// any changes here should also be made in src/view/primitives.rs
|
||||
|
@ -26,9 +27,9 @@ macro_rules! render_primitive {
|
|||
($($child_type:ty),* $(,)?) => {
|
||||
$(
|
||||
paste::paste! {
|
||||
pub struct [<SignalReadGuard $child_type:camel State>]<R>(R::Text, $child_type) where R: Renderer;
|
||||
pub struct [<ReadGuard $child_type:camel State>]<R>(R::Text, $child_type) where R: Renderer;
|
||||
|
||||
impl<'a, R: Renderer> Mountable<R> for [<SignalReadGuard $child_type:camel State>]<R> {
|
||||
impl<'a, R: Renderer> Mountable<R> for [<ReadGuard $child_type:camel State>]<R> {
|
||||
fn unmount(&mut self) {
|
||||
self.0.unmount()
|
||||
}
|
||||
|
@ -51,16 +52,18 @@ macro_rules! render_primitive {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, R: Renderer> Render<R> for SignalReadGuard<$child_type> {
|
||||
type State = [<SignalReadGuard $child_type:camel State>]<R>;
|
||||
impl<'a, G, R: Renderer> Render<R> for ReadGuard<$child_type, G>
|
||||
where G: Deref<Target = $child_type>
|
||||
{
|
||||
type State = [<ReadGuard $child_type:camel State>]<R>;
|
||||
|
||||
fn build(self) -> Self::State {
|
||||
let node = R::create_text_node(&self.to_string());
|
||||
[<SignalReadGuard $child_type:camel State>](node, *self)
|
||||
[<ReadGuard $child_type:camel State>](node, *self)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let [<SignalReadGuard $child_type:camel State>](node, this) = state;
|
||||
let [<ReadGuard $child_type:camel State>](node, this) = state;
|
||||
if &self != this {
|
||||
R::set_text(node, &self.to_string());
|
||||
*this = *self;
|
||||
|
@ -68,13 +71,14 @@ macro_rules! render_primitive {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> InfallibleRender for SignalReadGuard<$child_type> {}
|
||||
impl<'a, G> InfallibleRender for ReadGuard<$child_type, G> {}
|
||||
|
||||
impl<'a, R> RenderHtml<R> for SignalReadGuard<$child_type>
|
||||
impl<'a, G, R> RenderHtml<R> for ReadGuard<$child_type, G>
|
||||
where
|
||||
R: Renderer,
|
||||
R::Node: Clone,
|
||||
R::Element: Clone,
|
||||
G: Deref<Target = $child_type>
|
||||
{
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
|
@ -112,11 +116,12 @@ macro_rules! render_primitive {
|
|||
}
|
||||
position.set(Position::NextChildAfterText);
|
||||
|
||||
[<SignalReadGuard $child_type:camel State>](node, *self)
|
||||
[<ReadGuard $child_type:camel State>](node, *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToTemplate for SignalReadGuard<$child_type> {
|
||||
impl<'a, G> ToTemplate for ReadGuard<$child_type, G>
|
||||
{
|
||||
const TEMPLATE: &'static str = " <!>";
|
||||
|
||||
fn to_template(
|
||||
|
@ -176,24 +181,27 @@ render_primitive![
|
|||
];
|
||||
|
||||
// strings
|
||||
pub struct SignalReadGuardStringState<R: Renderer> {
|
||||
pub struct ReadGuardStringState<R: Renderer> {
|
||||
node: R::Text,
|
||||
str: String,
|
||||
}
|
||||
|
||||
impl<R: Renderer> Render<R> for SignalReadGuard<String> {
|
||||
type State = SignalReadGuardStringState<R>;
|
||||
impl<G, R: Renderer> Render<R> for ReadGuard<String, G>
|
||||
where
|
||||
G: Deref<Target = String>,
|
||||
{
|
||||
type State = ReadGuardStringState<R>;
|
||||
|
||||
fn build(self) -> Self::State {
|
||||
let node = R::create_text_node(&self);
|
||||
SignalReadGuardStringState {
|
||||
ReadGuardStringState {
|
||||
node,
|
||||
str: self.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let SignalReadGuardStringState { node, str } = state;
|
||||
let ReadGuardStringState { node, str } = state;
|
||||
if *self != *str {
|
||||
R::set_text(node, &self);
|
||||
str.clear();
|
||||
|
@ -202,13 +210,14 @@ impl<R: Renderer> Render<R> for SignalReadGuard<String> {
|
|||
}
|
||||
}
|
||||
|
||||
impl InfallibleRender for SignalReadGuard<String> {}
|
||||
impl<G> InfallibleRender for ReadGuard<String, G> {}
|
||||
|
||||
impl<R> RenderHtml<R> for SignalReadGuard<String>
|
||||
impl<G, R> RenderHtml<R> for ReadGuard<String, G>
|
||||
where
|
||||
R: Renderer,
|
||||
R::Node: Clone,
|
||||
R::Element: Clone,
|
||||
G: Deref<Target = String>,
|
||||
{
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
|
@ -224,14 +233,14 @@ where
|
|||
let this: &str = self.as_ref();
|
||||
let StrState { node, .. } =
|
||||
this.hydrate::<FROM_SERVER>(cursor, position);
|
||||
SignalReadGuardStringState {
|
||||
ReadGuardStringState {
|
||||
node,
|
||||
str: self.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTemplate for SignalReadGuard<String> {
|
||||
impl<G> ToTemplate for ReadGuard<String, G> {
|
||||
const TEMPLATE: &'static str = <&str as ToTemplate>::TEMPLATE;
|
||||
|
||||
fn to_template(
|
||||
|
@ -247,7 +256,7 @@ impl ToTemplate for SignalReadGuard<String> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<R: Renderer> Mountable<R> for SignalReadGuardStringState<R> {
|
||||
impl<R: Renderer> Mountable<R> for ReadGuardStringState<R> {
|
||||
fn unmount(&mut self) {
|
||||
self.node.unmount()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue