mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
working on examples
This commit is contained in:
parent
d726b56b71
commit
eea971b9fe
16 changed files with 460 additions and 97 deletions
|
@ -1,4 +1,4 @@
|
|||
use leptos::*;
|
||||
use leptos::prelude::*;
|
||||
|
||||
const MANY_COUNTERS: usize = 1000;
|
||||
|
||||
|
@ -77,39 +77,23 @@ pub fn Counters() -> impl IntoView {
|
|||
}
|
||||
|
||||
#[component]
|
||||
fn Counter(
|
||||
id: usize,
|
||||
value: ReadSignal<i32>,
|
||||
set_value: WriteSignal<i32>,
|
||||
) -> impl IntoView {
|
||||
fn Counter(id: usize, value: ArcRwSignal<i32>) -> impl IntoView {
|
||||
let value = RwSignal::from(value);
|
||||
let CounterUpdater { set_counters } = use_context().unwrap();
|
||||
|
||||
let input = move |ev| {
|
||||
set_value
|
||||
.set(event_target_value(&ev).parse::<i32>().unwrap_or_default())
|
||||
value.set(event_target_value(&ev).parse::<i32>().unwrap_or_default())
|
||||
};
|
||||
|
||||
// this will run when the scope is disposed, i.e., when this row is deleted
|
||||
// because the signal was created in the parent scope, it won't be disposed
|
||||
// of until the parent scope is. but we no longer need it, so we'll dispose of
|
||||
// it when this row is deleted, instead. if we don't dispose of it here,
|
||||
// this memory will "leak," i.e., the signal will continue to exist until the
|
||||
// parent component is removed. in the case of this component, where it's the
|
||||
// root, that's the lifetime of the program.
|
||||
on_cleanup(move || {
|
||||
log::debug!("deleted a row");
|
||||
value.dispose();
|
||||
});
|
||||
|
||||
view! {
|
||||
<li>
|
||||
<button on:click=move |_| set_value.update(move |value| *value -= 1)>"-1"</button>
|
||||
<button on:click=move |_| value.update(move |value| *value -= 1)>"-1"</button>
|
||||
<input type="text"
|
||||
prop:value={value}
|
||||
on:input=input
|
||||
/>
|
||||
<span>{value}</span>
|
||||
<button on:click=move |_| set_value.update(move |value| *value += 1)>"+1"</button>
|
||||
<button on:click=move |_| value.update(move |value| *value += 1)>"+1"</button>
|
||||
<button on:click=move |_| set_counters.update(move |counters| counters.retain(|(counter_id, _)| counter_id != &id))>"x"</button>
|
||||
</li>
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
ToAnySource, ToAnySubscriber,
|
||||
},
|
||||
signal::MappedSignalReadGuard,
|
||||
traits::{DefinedAt, Readable},
|
||||
traits::{DefinedAt, ReadUntracked},
|
||||
};
|
||||
use core::fmt::Debug;
|
||||
use or_poisoned::OrPoisoned;
|
||||
|
@ -158,10 +158,10 @@ impl<T: Send + Sync + 'static> Subscriber for ArcMemo<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> Readable for ArcMemo<T> {
|
||||
impl<T: Send + Sync + 'static> ReadUntracked for ArcMemo<T> {
|
||||
type Value = MappedSignalReadGuard<MemoInner<T>, T>;
|
||||
|
||||
fn try_read(&self) -> Option<Self::Value> {
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
self.update_if_necessary();
|
||||
|
||||
MappedSignalReadGuard::try_new(Arc::clone(&self.inner), |t| {
|
||||
|
|
|
@ -11,7 +11,7 @@ use crate::{
|
|||
},
|
||||
owner::Owner,
|
||||
signal::SignalReadGuard,
|
||||
traits::{DefinedAt, Readable},
|
||||
traits::{DefinedAt, ReadUntracked},
|
||||
};
|
||||
use core::fmt::Debug;
|
||||
use futures::{FutureExt, StreamExt};
|
||||
|
@ -221,10 +221,10 @@ impl<T: 'static> ArcAsyncDerived<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> Readable for ArcAsyncDerived<T> {
|
||||
impl<T: 'static> ReadUntracked for ArcAsyncDerived<T> {
|
||||
type Value = SignalReadGuard<AsyncState<T>>;
|
||||
|
||||
fn try_read(&self) -> Option<Self::Value> {
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
SignalReadGuard::try_new(Arc::clone(&self.value))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
},
|
||||
owner::{Stored, StoredData},
|
||||
signal::{MappedSignalReadGuard, SignalReadGuard},
|
||||
traits::{DefinedAt, Readable},
|
||||
traits::{DefinedAt, ReadUntracked},
|
||||
unwrap_signal,
|
||||
};
|
||||
use core::fmt::Debug;
|
||||
|
@ -146,11 +146,11 @@ impl<T: Send + Sync + Clone + 'static> IntoFuture for AsyncDerived<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> Readable for AsyncDerived<T> {
|
||||
impl<T: Send + Sync + 'static> ReadUntracked for AsyncDerived<T> {
|
||||
type Value = SignalReadGuard<AsyncState<T>>;
|
||||
|
||||
fn try_read(&self) -> Option<Self::Value> {
|
||||
self.get_value().map(|inner| inner.read())
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
self.get_value().map(|inner| inner.read_untracked())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use super::{inner::MemoInner, ArcMemo};
|
|||
use crate::{
|
||||
owner::{Stored, StoredData},
|
||||
signal::MappedSignalReadGuard,
|
||||
traits::{DefinedAt, Readable, Track},
|
||||
traits::{DefinedAt, ReadUntracked, Track},
|
||||
};
|
||||
use std::{fmt::Debug, panic::Location};
|
||||
|
||||
|
@ -80,10 +80,10 @@ impl<T: Send + Sync + 'static> Track for Memo<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> Readable for Memo<T> {
|
||||
impl<T: Send + Sync + 'static> ReadUntracked for Memo<T> {
|
||||
type Value = MappedSignalReadGuard<MemoInner<T>, T>;
|
||||
|
||||
fn try_read(&self) -> Option<Self::Value> {
|
||||
self.get_value().map(|inner| inner.read())
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
self.get_value().map(|inner| inner.read_untracked())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
ArcReadSignal, ArcRwSignal, ArcWriteSignal, ReadSignal, RwSignal,
|
||||
WriteSignal,
|
||||
},
|
||||
traits::{Readable, Set},
|
||||
traits::{Read, Set},
|
||||
};
|
||||
|
||||
macro_rules! impl_get_fn_traits {
|
||||
|
@ -12,7 +12,7 @@ macro_rules! impl_get_fn_traits {
|
|||
$(
|
||||
#[cfg(feature = "nightly")]
|
||||
impl<T: 'static> FnOnce<()> for $ty<T> {
|
||||
type Output = <Self as Readable>::Value;
|
||||
type Output = <Self as Read>::Value;
|
||||
|
||||
#[inline(always)]
|
||||
extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
|
||||
|
@ -88,7 +88,7 @@ macro_rules! impl_get_fn_traits_send {
|
|||
$(
|
||||
#[cfg(feature = "nightly")]
|
||||
impl<T: Send + Sync + 'static> FnOnce<()> for $ty<T> {
|
||||
type Output = <Self as Readable>::Value;
|
||||
type Output = <Self as Read>::Value;
|
||||
|
||||
#[inline(always)]
|
||||
extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::{subscriber_traits::AsSubscriberSet, SignalReadGuard};
|
||||
use crate::{
|
||||
graph::SubscriberSet,
|
||||
traits::{DefinedAt, IsDisposed, Readable},
|
||||
traits::{DefinedAt, IsDisposed, ReadUntracked},
|
||||
};
|
||||
use core::fmt::{Debug, Formatter, Result};
|
||||
use std::{
|
||||
|
@ -82,10 +82,10 @@ impl<T> AsSubscriberSet for ArcReadSignal<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> Readable for ArcReadSignal<T> {
|
||||
impl<T: 'static> ReadUntracked for ArcReadSignal<T> {
|
||||
type Value = SignalReadGuard<T>;
|
||||
|
||||
fn try_read(&self) -> Option<Self::Value> {
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
SignalReadGuard::try_new(Arc::clone(&self.value))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use super::{
|
|||
use crate::{
|
||||
graph::{ReactiveNode, SubscriberSet},
|
||||
prelude::{IsDisposed, Trigger},
|
||||
traits::{DefinedAt, Readable, Writeable},
|
||||
traits::{DefinedAt, ReadUntracked, Writeable},
|
||||
};
|
||||
use core::fmt::{Debug, Formatter, Result};
|
||||
use std::{
|
||||
|
@ -112,10 +112,10 @@ impl<T> AsSubscriberSet for ArcRwSignal<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> Readable for ArcRwSignal<T> {
|
||||
impl<T: 'static> ReadUntracked for ArcRwSignal<T> {
|
||||
type Value = SignalReadGuard<T>;
|
||||
|
||||
fn try_read(&self) -> Option<Self::Value> {
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
SignalReadGuard::try_new(Arc::clone(&self.value))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,8 @@ use super::{
|
|||
use crate::{
|
||||
graph::SubscriberSet,
|
||||
owner::{Stored, StoredData},
|
||||
traits::{DefinedAt, IsDisposed, Readable},
|
||||
traits::{DefinedAt, IsDisposed, ReadUntracked},
|
||||
unwrap_signal,
|
||||
};
|
||||
use core::fmt::Debug;
|
||||
use std::{
|
||||
|
@ -76,10 +77,28 @@ impl<T: Send + Sync + 'static> AsSubscriberSet for ReadSignal<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> Readable for ReadSignal<T> {
|
||||
impl<T: Send + Sync + 'static> ReadUntracked for ReadSignal<T> {
|
||||
type Value = SignalReadGuard<T>;
|
||||
|
||||
fn try_read(&self) -> Option<Self::Value> {
|
||||
self.get_value().map(|inner| inner.read())
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
self.get_value().map(|inner| inner.read_untracked())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> From<ArcReadSignal<T>> for ReadSignal<T> {
|
||||
#[track_caller]
|
||||
fn from(value: ArcReadSignal<T>) -> Self {
|
||||
ReadSignal {
|
||||
#[cfg(debug_assertions)]
|
||||
defined_at: Location::caller(),
|
||||
inner: Stored::new(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> From<ReadSignal<T>> for ArcReadSignal<T> {
|
||||
#[track_caller]
|
||||
fn from(value: ReadSignal<T>) -> Self {
|
||||
value.get_value().unwrap_or_else(unwrap_signal!(value))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use super::{
|
|||
use crate::{
|
||||
graph::{ReactiveNode, SubscriberSet},
|
||||
owner::{Stored, StoredData},
|
||||
traits::{DefinedAt, IsDisposed, Readable, Trigger, UpdateUntracked},
|
||||
traits::{DefinedAt, IsDisposed, ReadUntracked, Trigger, UpdateUntracked},
|
||||
unwrap_signal,
|
||||
};
|
||||
use core::fmt::Debug;
|
||||
|
@ -146,11 +146,11 @@ impl<T: Send + Sync + 'static> AsSubscriberSet for RwSignal<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> Readable for RwSignal<T> {
|
||||
impl<T: Send + Sync + 'static> ReadUntracked for RwSignal<T> {
|
||||
type Value = SignalReadGuard<T>;
|
||||
|
||||
fn try_read(&self) -> Option<Self::Value> {
|
||||
self.get_value().map(|inner| inner.read())
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
self.get_value().map(|inner| inner.read_untracked())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,3 +170,21 @@ impl<T: Send + Sync + 'static> UpdateUntracked for RwSignal<T> {
|
|||
self.get_value().and_then(|n| n.try_update_untracked(fun))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> From<ArcRwSignal<T>> for RwSignal<T> {
|
||||
#[track_caller]
|
||||
fn from(value: ArcRwSignal<T>) -> Self {
|
||||
RwSignal {
|
||||
#[cfg(debug_assertions)]
|
||||
defined_at: Location::caller(),
|
||||
inner: Stored::new(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> From<RwSignal<T>> for ArcRwSignal<T> {
|
||||
#[track_caller]
|
||||
fn from(value: RwSignal<T>) -> Self {
|
||||
value.get_value().unwrap_or_else(unwrap_signal!(value))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,20 +13,20 @@
|
|||
//! - [`IsDisposed`] checks whether a signal is currently accessible.
|
||||
//!
|
||||
//! ## Base Traits
|
||||
//! | Trait | Mode | Description |
|
||||
//! |--------------|-------|---------------------------------------------------------------------------------------|
|
||||
//! | [`Track`] | — | Tracks changes to this value, adding it as a source of the current reactive observer. |
|
||||
//! | [`Trigger`] | — | Notifies subscribers that this value has changed. |
|
||||
//! | [`Readable`] | Guard | Gives immutable access to the value of this signal. |
|
||||
//! | [`Writeable`]| Guard | Gives mutable access to the value of this signal.
|
||||
//! | Trait | Mode | Description |
|
||||
//! |-------------------|-------|---------------------------------------------------------------------------------------|
|
||||
//! | [`Track`] | — | Tracks changes to this value, adding it as a source of the current reactive observer. |
|
||||
//! | [`Trigger`] | — | Notifies subscribers that this value has changed. |
|
||||
//! | [`ReadUntracked`] | Guard | Gives immutable access to the value of this signal. |
|
||||
//! | [`Writeable`] | Guard | Gives mutable access to the value of this signal.
|
||||
//!
|
||||
//! ## Derived Traits
|
||||
//!
|
||||
//! ### Access
|
||||
//! | Trait | Mode | Composition | Description
|
||||
//! |-------------------|---------------|-------------------------------|------------
|
||||
//! | [`WithUntracked`] | `fn(&T) -> U` | [`Readable`] | Applies closure to the current value of the signal and returns result.
|
||||
//! | [`With`] | `fn(&T) -> U` | [`Readable`] + [`Track`] | Applies closure to the current value of the signal and returns result, with reactive tracking.
|
||||
//! | [`WithUntracked`] | `fn(&T) -> U` | [`ReadUntracked`] | Applies closure to the current value of the signal and returns result.
|
||||
//! | [`With`] | `fn(&T) -> U` | [`ReadUntracked`] + [`Track`] | Applies closure to the current value of the signal and returns result, with reactive tracking.
|
||||
//! | [`GetUntracked`] | `T` | [`WithUntracked`] + [`Clone`] | Clones the current value of the signal.
|
||||
//! | [`Get`] | `T` | [`GetUntracked`] + [`Track`] | Clones the current value of the signal, with reactive tracking.
|
||||
//!
|
||||
|
@ -42,9 +42,9 @@
|
|||
//! These traits are designed so that you can implement as few as possible, and the rest will be
|
||||
//! implemented automatically.
|
||||
//!
|
||||
//! For example, if you have a struct for which you can implement [`Readable`] and [`Track`], then
|
||||
//! For example, if you have a struct for which you can implement [`ReadUntracked`] and [`Track`], then
|
||||
//! [`WithUntracked`] and [`With`] will be implemented automatically (as will [`GetUntracked`] and
|
||||
//! [`Get`] for `Clone` types). But if you cannot implement [`Readable`] (because, for example,
|
||||
//! [`Get`] for `Clone` types). But if you cannot implement [`ReadUntracked`] (because, for example,
|
||||
//! there isn't an `RwLock` you can wrap in a [`SignalReadGuard`](crate::signal::SignalReadGuard),
|
||||
//! but you can still implement [`WithUntracked`] and [`Track`], the same traits will still be implemented.
|
||||
|
||||
|
@ -95,15 +95,43 @@ impl<T: Source + ToAnySource> Track for T {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait Readable: Sized + DefinedAt {
|
||||
pub trait ReadUntracked: Sized + DefinedAt {
|
||||
type Value: Deref;
|
||||
|
||||
#[track_caller]
|
||||
fn try_read_untracked(&self) -> Option<Self::Value>;
|
||||
|
||||
#[track_caller]
|
||||
fn read_untracked(&self) -> Self::Value {
|
||||
self.try_read_untracked()
|
||||
.unwrap_or_else(unwrap_signal!(self))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Read {
|
||||
type Value: Deref;
|
||||
|
||||
#[track_caller]
|
||||
fn try_read(&self) -> Option<Self::Value>;
|
||||
|
||||
#[track_caller]
|
||||
fn read(&self) -> Self::Value;
|
||||
}
|
||||
|
||||
impl<T> Read for T
|
||||
where
|
||||
T: Track + ReadUntracked,
|
||||
{
|
||||
type Value = T::Value;
|
||||
|
||||
fn try_read(&self) -> Option<Self::Value> {
|
||||
self.track();
|
||||
self.try_read_untracked()
|
||||
}
|
||||
|
||||
fn read(&self) -> Self::Value {
|
||||
self.try_read().unwrap_or_else(unwrap_signal!(self))
|
||||
self.track();
|
||||
self.read_untracked()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,15 +172,15 @@ pub trait WithUntracked: DefinedAt {
|
|||
|
||||
impl<T> WithUntracked for T
|
||||
where
|
||||
T: DefinedAt + Readable,
|
||||
T: DefinedAt + ReadUntracked,
|
||||
{
|
||||
type Value = <<Self as Readable>::Value as Deref>::Target;
|
||||
type Value = <<Self as ReadUntracked>::Value as Deref>::Target;
|
||||
|
||||
fn try_with_untracked<U>(
|
||||
&self,
|
||||
fun: impl FnOnce(&Self::Value) -> U,
|
||||
) -> Option<U> {
|
||||
self.try_read().map(|value| fun(&value))
|
||||
self.try_read_untracked().map(|value| fun(&value))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use reactive_graph::{
|
|||
computed::{ArcAsyncDerived, AsyncDerived, AsyncState},
|
||||
executor::Executor,
|
||||
signal::RwSignal,
|
||||
traits::{Get, Readable, Set, With, WithUntracked},
|
||||
traits::{Get, Read, Set, With, WithUntracked},
|
||||
};
|
||||
|
||||
#[cfg(feature = "tokio")]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use reactive_graph::{
|
||||
signal::{arc_signal, signal, ArcRwSignal, RwSignal},
|
||||
traits::{
|
||||
Get, GetUntracked, Readable, Set, Update, UpdateUntracked, With,
|
||||
Get, GetUntracked, Read, Set, Update, UpdateUntracked, With,
|
||||
WithUntracked, Writeable,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,46 +1,271 @@
|
|||
//! Implements the [`Render`] and [`RenderHtml`] traits for signal guard types.
|
||||
|
||||
use crate::{prelude::RenderHtml, renderer::Renderer, view::Render};
|
||||
use crate::{
|
||||
hydration::Cursor,
|
||||
prelude::RenderHtml,
|
||||
renderer::{CastFrom, Renderer},
|
||||
view::{
|
||||
strings::StrState, InfallibleRender, Mountable, Position,
|
||||
PositionState, Render, ToTemplate,
|
||||
},
|
||||
};
|
||||
use reactive_graph::signal::SignalReadGuard;
|
||||
use std::{
|
||||
fmt::Write,
|
||||
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
|
||||
num::{
|
||||
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8,
|
||||
NonZeroIsize, NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64,
|
||||
NonZeroU8, NonZeroUsize,
|
||||
},
|
||||
};
|
||||
|
||||
impl<T, Rndr> Render<Rndr> for SignalReadGuard<T>
|
||||
where
|
||||
T: PartialEq + Clone + Render<Rndr>,
|
||||
Rndr: Renderer,
|
||||
{
|
||||
type State = T::State;
|
||||
// any changes here should also be made in src/view/primitives.rs
|
||||
macro_rules! render_primitive {
|
||||
($($child_type:ty),* $(,)?) => {
|
||||
$(
|
||||
paste::paste! {
|
||||
pub struct [<SignalReadGuard $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> {
|
||||
fn unmount(&mut self) {
|
||||
self.0.unmount()
|
||||
}
|
||||
|
||||
fn mount(
|
||||
&mut self,
|
||||
parent: &<R as Renderer>::Element,
|
||||
marker: Option<&<R as Renderer>::Node>,
|
||||
) {
|
||||
R::insert_node(parent, self.0.as_ref(), marker);
|
||||
}
|
||||
|
||||
fn insert_before_this(
|
||||
&self,
|
||||
parent: &<R as Renderer>::Element,
|
||||
child: &mut dyn Mountable<R>,
|
||||
) -> bool {
|
||||
child.mount(parent, Some(self.0.as_ref()));
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: Renderer> Render<R> for SignalReadGuard<$child_type> {
|
||||
type State = [<SignalReadGuard $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)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let [<SignalReadGuard $child_type:camel State>](node, this) = state;
|
||||
if &self != this {
|
||||
crate::log(&format!("not equal"));
|
||||
R::set_text(node, &self.to_string());
|
||||
*this = *self;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> InfallibleRender for SignalReadGuard<$child_type> {}
|
||||
|
||||
impl<'a, R> RenderHtml<R> for SignalReadGuard<$child_type>
|
||||
where
|
||||
R: Renderer,
|
||||
R::Node: Clone,
|
||||
R::Element: Clone,
|
||||
{
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn to_html_with_buf(self, buf: &mut String, position: &mut Position) {
|
||||
// add a comment node to separate from previous sibling, if any
|
||||
if matches!(position, Position::NextChildAfterText) {
|
||||
buf.push_str("<!>")
|
||||
}
|
||||
write!(buf, "{}", self);
|
||||
*position = Position::NextChildAfterText;
|
||||
}
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(
|
||||
self,
|
||||
cursor: &Cursor<R>,
|
||||
position: &PositionState,
|
||||
) -> Self::State {
|
||||
if position.get() == Position::FirstChild {
|
||||
cursor.child();
|
||||
} else {
|
||||
cursor.sibling();
|
||||
}
|
||||
|
||||
// separating placeholder marker comes before text node
|
||||
if matches!(position.get(), Position::NextChildAfterText) {
|
||||
cursor.sibling();
|
||||
}
|
||||
|
||||
let node = cursor.current();
|
||||
let node = R::Text::cast_from(node)
|
||||
.expect("couldn't cast text node from node");
|
||||
|
||||
if !FROM_SERVER {
|
||||
R::set_text(&node, &self.to_string());
|
||||
}
|
||||
position.set(Position::NextChildAfterText);
|
||||
|
||||
[<SignalReadGuard $child_type:camel State>](node, *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToTemplate for SignalReadGuard<$child_type> {
|
||||
const TEMPLATE: &'static str = " <!>";
|
||||
|
||||
fn to_template(
|
||||
buf: &mut String,
|
||||
_class: &mut String,
|
||||
_style: &mut String,
|
||||
_inner_html: &mut String,
|
||||
position: &mut Position,
|
||||
) {
|
||||
if matches!(*position, Position::NextChildAfterText) {
|
||||
buf.push_str("<!>")
|
||||
}
|
||||
buf.push(' ');
|
||||
*position = Position::NextChildAfterText;
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
render_primitive![
|
||||
usize,
|
||||
u8,
|
||||
u16,
|
||||
u32,
|
||||
u64,
|
||||
u128,
|
||||
isize,
|
||||
i8,
|
||||
i16,
|
||||
i32,
|
||||
i64,
|
||||
i128,
|
||||
f32,
|
||||
f64,
|
||||
char,
|
||||
bool,
|
||||
IpAddr,
|
||||
SocketAddr,
|
||||
SocketAddrV4,
|
||||
SocketAddrV6,
|
||||
Ipv4Addr,
|
||||
Ipv6Addr,
|
||||
NonZeroI8,
|
||||
NonZeroU8,
|
||||
NonZeroI16,
|
||||
NonZeroU16,
|
||||
NonZeroI32,
|
||||
NonZeroU32,
|
||||
NonZeroI64,
|
||||
NonZeroU64,
|
||||
NonZeroI128,
|
||||
NonZeroU128,
|
||||
NonZeroIsize,
|
||||
NonZeroUsize,
|
||||
];
|
||||
|
||||
// strings
|
||||
pub struct SignalReadGuardStringState<R: Renderer> {
|
||||
node: R::Text,
|
||||
str: String,
|
||||
}
|
||||
|
||||
impl<R: Renderer> Render<R> for SignalReadGuard<String> {
|
||||
type State = SignalReadGuardStringState<R>;
|
||||
|
||||
fn build(self) -> Self::State {
|
||||
todo!()
|
||||
let node = R::create_text_node(&self);
|
||||
SignalReadGuardStringState {
|
||||
node,
|
||||
str: self.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
todo!()
|
||||
let SignalReadGuardStringState { node, str } = state;
|
||||
if *self != *str {
|
||||
R::set_text(node, &self);
|
||||
str.clear();
|
||||
str.push_str(&self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Rndr> RenderHtml<Rndr> for SignalReadGuard<T>
|
||||
where
|
||||
T: PartialEq + Clone + RenderHtml<Rndr>,
|
||||
Rndr: Renderer,
|
||||
Rndr::Element: Clone,
|
||||
Rndr::Node: Clone,
|
||||
{
|
||||
const MIN_LENGTH: usize = T::MIN_LENGTH;
|
||||
impl InfallibleRender for SignalReadGuard<String> {}
|
||||
|
||||
fn to_html_with_buf(
|
||||
self,
|
||||
buf: &mut String,
|
||||
position: &mut crate::view::Position,
|
||||
) {
|
||||
todo!()
|
||||
impl<R> RenderHtml<R> for SignalReadGuard<String>
|
||||
where
|
||||
R: Renderer,
|
||||
R::Node: Clone,
|
||||
R::Element: Clone,
|
||||
{
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn to_html_with_buf(self, buf: &mut String, position: &mut Position) {
|
||||
<&str as RenderHtml<R>>::to_html_with_buf(&self, buf, position)
|
||||
}
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(
|
||||
self,
|
||||
cursor: &crate::hydration::Cursor<Rndr>,
|
||||
position: &crate::view::PositionState,
|
||||
cursor: &Cursor<R>,
|
||||
position: &PositionState,
|
||||
) -> Self::State {
|
||||
todo!()
|
||||
let this: &str = self.as_ref();
|
||||
let StrState { node, .. } =
|
||||
this.hydrate::<FROM_SERVER>(cursor, position);
|
||||
SignalReadGuardStringState {
|
||||
node,
|
||||
str: self.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTemplate for SignalReadGuard<String> {
|
||||
const TEMPLATE: &'static str = <&str as ToTemplate>::TEMPLATE;
|
||||
|
||||
fn to_template(
|
||||
buf: &mut String,
|
||||
class: &mut String,
|
||||
style: &mut String,
|
||||
inner_html: &mut String,
|
||||
position: &mut Position,
|
||||
) {
|
||||
<&str as ToTemplate>::to_template(
|
||||
buf, class, style, inner_html, position,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Renderer> Mountable<R> for SignalReadGuardStringState<R> {
|
||||
fn unmount(&mut self) {
|
||||
self.node.unmount()
|
||||
}
|
||||
|
||||
fn mount(
|
||||
&mut self,
|
||||
parent: &<R as Renderer>::Element,
|
||||
marker: Option<&<R as Renderer>::Node>,
|
||||
) {
|
||||
R::insert_node(parent, self.node.as_ref(), marker);
|
||||
}
|
||||
|
||||
fn insert_before_this(
|
||||
&self,
|
||||
parent: &<R as Renderer>::Element,
|
||||
child: &mut dyn Mountable<R>,
|
||||
) -> bool {
|
||||
child.mount(parent, Some(self.node.as_ref()));
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ use std::{
|
|||
},
|
||||
};
|
||||
|
||||
// any changes here should also be made in src/reactive_graph/guards.rs
|
||||
macro_rules! render_primitive {
|
||||
($($child_type:ty),* $(,)?) => {
|
||||
$(
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
hydration::Cursor,
|
||||
renderer::{CastFrom, Renderer},
|
||||
};
|
||||
use std::{rc::Rc, sync::Arc};
|
||||
use std::{borrow::Cow, rc::Rc, sync::Arc};
|
||||
|
||||
pub struct StrState<'a, R: Renderer> {
|
||||
pub node: R::Text,
|
||||
|
@ -121,6 +121,7 @@ where
|
|||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StringState<R: Renderer> {
|
||||
node: R::Text,
|
||||
str: String,
|
||||
|
@ -380,3 +381,90 @@ impl<R: Renderer> Mountable<R> for ArcStrState<R> {
|
|||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CowStrState<'a, R: Renderer> {
|
||||
node: R::Text,
|
||||
str: Cow<'a, str>,
|
||||
}
|
||||
|
||||
impl<'a, R: Renderer> Render<R> for Cow<'a, str> {
|
||||
type State = CowStrState<'a, R>;
|
||||
|
||||
fn build(self) -> Self::State {
|
||||
let node = R::create_text_node(&self);
|
||||
CowStrState { node, str: self }
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let CowStrState { node, str } = state;
|
||||
if self != *str {
|
||||
R::set_text(node, &self);
|
||||
*str = self;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> InfallibleRender for Cow<'a, str> {}
|
||||
|
||||
impl<'a, R> RenderHtml<R> for Cow<'a, str>
|
||||
where
|
||||
R: Renderer,
|
||||
R::Node: Clone,
|
||||
R::Element: Clone,
|
||||
{
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn to_html_with_buf(self, buf: &mut String, position: &mut Position) {
|
||||
<&str as RenderHtml<R>>::to_html_with_buf(&self, buf, position)
|
||||
}
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(
|
||||
self,
|
||||
cursor: &Cursor<R>,
|
||||
position: &PositionState,
|
||||
) -> Self::State {
|
||||
let this: &str = self.as_ref();
|
||||
let StrState { node, .. } =
|
||||
this.hydrate::<FROM_SERVER>(cursor, position);
|
||||
CowStrState { node, str: self }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToTemplate for Cow<'a, str> {
|
||||
const TEMPLATE: &'static str = <&str as ToTemplate>::TEMPLATE;
|
||||
|
||||
fn to_template(
|
||||
buf: &mut String,
|
||||
class: &mut String,
|
||||
style: &mut String,
|
||||
inner_html: &mut String,
|
||||
position: &mut Position,
|
||||
) {
|
||||
<&str as ToTemplate>::to_template(
|
||||
buf, class, style, inner_html, position,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: Renderer> Mountable<R> for CowStrState<'a, R> {
|
||||
fn unmount(&mut self) {
|
||||
self.node.unmount()
|
||||
}
|
||||
|
||||
fn mount(
|
||||
&mut self,
|
||||
parent: &<R as Renderer>::Element,
|
||||
marker: Option<&<R as Renderer>::Node>,
|
||||
) {
|
||||
R::insert_node(parent, self.node.as_ref(), marker);
|
||||
}
|
||||
|
||||
fn insert_before_this(
|
||||
&self,
|
||||
parent: &<R as Renderer>::Element,
|
||||
child: &mut dyn Mountable<R>,
|
||||
) -> bool {
|
||||
child.mount(parent, Some(self.node.as_ref()));
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue