This commit is contained in:
Greg Johnston 2024-05-03 15:39:15 -04:00
parent 45fd9423f8
commit 3c13280bf6
40 changed files with 1282 additions and 178 deletions

View file

@ -76,8 +76,7 @@ impl<T: IntoView> RenderHtml<Dom> for View<T> {
}
}
/*
impl<T: AddAnyAttr<Dom>> AddAnyAttr<Dom> for View<T> {
impl<T: IntoView> AddAnyAttr<Dom> for View<T> {
type Output<SomeNewAttr: Attribute<Dom>> =
<T as AddAnyAttr<Dom>>::Output<SomeNewAttr>;
@ -90,14 +89,4 @@ impl<T: AddAnyAttr<Dom>> AddAnyAttr<Dom> for View<T> {
{
self.0.add_any_attr(attr)
}
fn add_any_attr_by_ref<NewAttr: Attribute<Dom>>(
self,
attr: &NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<Dom>,
{
self.0.add_any_attr_by_ref(attr)
}
}*/
}

View file

@ -25,6 +25,7 @@ impl ToAnySubscriber for Arc<RwLock<EffectInner>> {
impl ReactiveNode for RwLock<EffectInner> {
fn mark_subscribers_check(&self) {}
// TODO check if this actually works for memos
fn update_if_necessary(&self) -> bool {
let sources = {
let guard = self.read().or_poisoned();

View file

@ -3,6 +3,7 @@ use core::{fmt::Debug, hash::Hash};
use std::{cell::RefCell, mem, sync::Weak};
thread_local! {
// TODO this can be a Cell
static OBSERVER: RefCell<Option<AnySubscriber>> = const { RefCell::new(None) };
}

View file

@ -24,6 +24,18 @@ impl<T, Inner> ReadGuard<T, Inner> {
}
}
impl<T, Inner> Clone for ReadGuard<T, Inner>
where
Inner: Clone,
{
fn clone(&self) -> Self {
Self {
ty: self.ty,
inner: self.inner.clone(),
}
}
}
impl<T, Inner> Deref for ReadGuard<T, Inner>
where
Inner: Deref<Target = T>,

View file

@ -1,10 +1,11 @@
use crate::{
html::attribute::Attribute,
hydration::Cursor,
renderer::Renderer,
ssr::StreamBuilder,
view::{
either::EitherState, Mountable, Position, PositionState, Render,
RenderHtml,
add_attr::AddAnyAttr, either::EitherState, Mountable, Position,
PositionState, Render, RenderHtml,
},
};
use any_spawner::Executor;
@ -146,6 +147,27 @@ where
}
}
impl<const TRANSITION: bool, Fal, Fut, Rndr> AddAnyAttr<Rndr>
for Suspend<TRANSITION, Fal, Fut>
where
Fal: RenderHtml<Rndr> + 'static,
Fut: Future + Send + 'static,
Fut::Output: RenderHtml<Rndr> + Send,
Rndr: Renderer + 'static,
{
type Output<SomeNewAttr: Attribute<Rndr>> = Self;
fn add_any_attr<NewAttr: Attribute<Rndr>>(
self,
_attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<Rndr>,
{
todo!()
}
}
impl<const TRANSITION: bool, Fal, Fut, Rndr> RenderHtml<Rndr>
for Suspend<TRANSITION, Fal, Fut>
where

View file

@ -162,6 +162,7 @@ where
type State = AnyAttributeState<R>;
type Cloneable = ();
type CloneableOwned = ();
fn html_len(&self) -> usize {
self.html_len
@ -199,4 +200,8 @@ where
fn into_cloneable(self) -> Self::Cloneable {
todo!()
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
todo!()
}
}

View file

@ -20,6 +20,7 @@ where
}
}
#[derive(Debug)]
pub struct CustomAttr<K, V, R>
where
K: CustomAttributeKey,
@ -31,6 +32,21 @@ where
rndr: PhantomData<R>,
}
impl<K, V, R> Clone for CustomAttr<K, V, R>
where
K: CustomAttributeKey,
V: AttributeValue<R> + Clone,
R: DomRenderer,
{
fn clone(&self) -> Self {
Self {
key: self.key.clone(),
value: self.value.clone(),
rndr: self.rndr.clone(),
}
}
}
impl<K, V, R> Attribute<R> for CustomAttr<K, V, R>
where
K: CustomAttributeKey,
@ -40,6 +56,7 @@ where
const MIN_LENGTH: usize = 0;
type State = V::State;
type Cloneable = CustomAttr<K, V::Cloneable, R>;
type CloneableOwned = CustomAttr<K, V::CloneableOwned, R>;
fn html_len(&self) -> usize {
self.key.as_ref().len() + 3 + self.value.html_len()
@ -78,6 +95,14 @@ where
rndr: self.rndr,
}
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
CustomAttr {
key: self.key,
value: self.value.into_cloneable_owned(),
rndr: self.rndr,
}
}
}
impl<K, V, R> NextAttribute<R> for CustomAttr<K, V, R>
@ -115,19 +140,16 @@ where
}
}
pub trait CustomAttributeKey: AsRef<str> + Send {
// TODO this needs to be a method, not a const
pub trait CustomAttributeKey: Clone + AsRef<str> + Send + 'static {
const KEY: &'static str;
}
impl<'a> CustomAttributeKey for &'a str {
impl CustomAttributeKey for &'static str {
const KEY: &'static str = "";
}
impl<'a> CustomAttributeKey for Cow<'a, str> {
const KEY: &'static str = "";
}
impl CustomAttributeKey for &String {
impl CustomAttributeKey for Cow<'static, str> {
const KEY: &'static str = "";
}

View file

@ -2,7 +2,7 @@ use super::{Attr, AttributeValue};
use crate::renderer::Renderer;
use std::{fmt::Debug, marker::PhantomData};
pub trait AttributeKey: Send {
pub trait AttributeKey: Clone + Send + 'static {
const KEY: &'static str;
}

View file

@ -16,7 +16,8 @@ pub trait Attribute<R: Renderer>: NextAttribute<R> + Send {
const MIN_LENGTH: usize;
type State;
type Cloneable;
type Cloneable: Attribute<R> + Clone;
type CloneableOwned: Attribute<R> + Clone + 'static;
fn html_len(&self) -> usize;
@ -35,6 +36,8 @@ pub trait Attribute<R: Renderer>: NextAttribute<R> + Send {
fn rebuild(self, state: &mut Self::State);
fn into_cloneable(self) -> Self::Cloneable;
fn into_cloneable_owned(self) -> Self::CloneableOwned;
}
pub trait NextAttribute<R: Renderer> {
@ -54,6 +57,7 @@ where
type State = ();
type Cloneable = ();
type CloneableOwned = ();
fn html_len(&self) -> usize {
0
@ -78,6 +82,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::Cloneable {
self
}
}
impl<R> NextAttribute<R> for ()
@ -101,6 +109,17 @@ where
V: AttributeValue<R>,
R: Renderer;
impl<K, V, R> Clone for Attr<K, V, R>
where
K: AttributeKey,
V: AttributeValue<R> + Clone,
R: Renderer,
{
fn clone(&self) -> Self {
Self(self.0.clone(), self.1.clone(), PhantomData)
}
}
impl<K, V, R> ToTemplate for Attr<K, V, R>
where
K: AttributeKey,
@ -128,6 +147,7 @@ where
type State = V::State;
type Cloneable = Attr<K, V::Cloneable, R>;
type CloneableOwned = Attr<K, V::CloneableOwned, R>;
fn html_len(&self) -> usize {
K::KEY.len() + 3 + self.1.html_len()
@ -158,6 +178,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
Attr(self.0, self.1.into_cloneable(), PhantomData)
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
Attr(self.0, self.1.into_cloneable_owned(), PhantomData)
}
}
impl<K, V, R> NextAttribute<R> for Attr<K, V, R>
@ -188,6 +212,7 @@ macro_rules! impl_attr_for_tuples {
type State = ($first::State, $($ty::State,)*);
type Cloneable = ($first::Cloneable, $($ty::Cloneable,)*);
type CloneableOwned = ($first::CloneableOwned, $($ty::CloneableOwned,)*);
fn html_len(&self) -> usize {
#[allow(non_snake_case)]
@ -239,6 +264,14 @@ macro_rules! impl_attr_for_tuples {
$($ty.into_cloneable()),*
)
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
let ($first, $($ty,)*) = self;
(
$first.into_cloneable_owned(),
$($ty.into_cloneable_owned()),*
)
}
}
impl<$first, $($ty),*, Rndr> NextAttribute<Rndr> for ($first, $($ty,)*)
@ -273,6 +306,7 @@ macro_rules! impl_attr_for_tuples_truncate_additional {
type State = ($first::State, $($ty::State,)*);
type Cloneable = ($first::Cloneable, $($ty::Cloneable,)*);
type CloneableOwned = ($first::CloneableOwned, $($ty::CloneableOwned,)*);
fn html_len(&self) -> usize {
#[allow(non_snake_case)]
@ -324,6 +358,14 @@ macro_rules! impl_attr_for_tuples_truncate_additional {
$($ty.into_cloneable()),*
)
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
let ($first, $($ty,)*) = self;
(
$first.into_cloneable_owned(),
$($ty.into_cloneable_owned()),*
)
}
}
impl<$first, $($ty),*, Rndr> NextAttribute<Rndr> for ($first, $($ty,)*)
@ -354,6 +396,7 @@ where
type State = A::State;
type Cloneable = (A::Cloneable,);
type CloneableOwned = (A::CloneableOwned,);
fn html_len(&self) -> usize {
self.0.html_len()
@ -387,6 +430,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
(self.0.into_cloneable(),)
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
(self.0.into_cloneable_owned(),)
}
}
impl<A, Rndr> NextAttribute<Rndr> for (A,)

View file

@ -21,6 +21,11 @@ pub trait AttributeValue<R: Renderer>: Send {
/// `Arc<str>`, as two different clones of a `String` will still have the same value.
type Cloneable: AttributeValue<R> + Clone;
/// A cloneable type that is also `'static`. This is used for spreading across types when the
/// spreadable attribute needs to be owned. In some cases (`&'a str` to `Arc<str>`, etc.) the owned
/// cloneable type has worse performance than the cloneable type, so they are separate.
type CloneableOwned: AttributeValue<R> + Clone + 'static;
fn html_len(&self) -> usize;
fn to_html(self, key: &str, buf: &mut String);
@ -38,6 +43,8 @@ pub trait AttributeValue<R: Renderer>: Send {
fn rebuild(self, key: &str, state: &mut Self::State);
fn into_cloneable(self) -> Self::Cloneable;
fn into_cloneable_owned(self) -> Self::CloneableOwned;
}
impl<R> AttributeValue<R> for ()
@ -46,6 +53,7 @@ where
{
type State = ();
type Cloneable = ();
type CloneableOwned = ();
fn html_len(&self) -> usize {
0
@ -64,6 +72,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
impl<'a, R> AttributeValue<R> for &'a str
@ -71,7 +83,8 @@ where
R: Renderer,
{
type State = (R::Element, &'a str);
type Cloneable = Self;
type Cloneable = &'a str;
type CloneableOwned = Arc<str>;
fn html_len(&self) -> usize {
self.len()
@ -116,6 +129,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.into()
}
}
#[cfg(feature = "nightly")]
@ -126,6 +143,7 @@ where
{
type State = ();
type Cloneable = Self;
type CloneableOwned = Self;
fn html_len(&self) -> usize {
V.len()
@ -159,6 +177,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
impl<'a, R> AttributeValue<R> for &'a String
@ -167,6 +189,7 @@ where
{
type State = (R::Element, &'a String);
type Cloneable = Self;
type CloneableOwned = Arc<str>;
fn html_len(&self) -> usize {
self.len()
@ -207,6 +230,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.as_str().into()
}
}
impl<R> AttributeValue<R> for String
@ -215,6 +242,7 @@ where
{
type State = (R::Element, String);
type Cloneable = Arc<str>;
type CloneableOwned = Arc<str>;
fn html_len(&self) -> usize {
self.len()
@ -255,6 +283,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self.into()
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.into()
}
}
impl<R> AttributeValue<R> for Arc<str>
@ -263,6 +295,7 @@ where
{
type State = (R::Element, Arc<str>);
type Cloneable = Arc<str>;
type CloneableOwned = Arc<str>;
fn html_len(&self) -> usize {
self.len()
@ -303,6 +336,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
// TODO impl AttributeValue for Rc<str> and Arc<str> too
@ -312,6 +349,7 @@ where
{
type State = (R::Element, bool);
type Cloneable = Self;
type CloneableOwned = Self;
fn html_len(&self) -> usize {
0
@ -361,6 +399,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
impl<V, R> AttributeValue<R> for Option<V>
@ -370,6 +412,7 @@ where
{
type State = (R::Element, Option<V::State>);
type Cloneable = Option<V::Cloneable>;
type CloneableOwned = Option<V::CloneableOwned>;
fn html_len(&self) -> usize {
match self {
@ -427,6 +470,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self.map(|value| value.into_cloneable())
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.map(|value| value.into_cloneable_owned())
}
}
fn escape_attr(value: &str) -> Cow<'_, str> {
@ -442,6 +489,7 @@ macro_rules! render_primitive {
{
type State = (R::Element, $child_type);
type Cloneable = Self;
type CloneableOwned = Self;
fn html_len(&self) -> usize {
0
@ -482,6 +530,10 @@ macro_rules! render_primitive {
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
)*
}

View file

@ -17,15 +17,24 @@ where
}
}
pub struct Class<C, R>
where
C: IntoClass<R>,
R: DomRenderer,
{
#[derive(Debug)]
pub struct Class<C, R> {
class: C,
rndr: PhantomData<R>,
}
impl<C, R> Clone for Class<C, R>
where
C: Clone,
{
fn clone(&self) -> Self {
Self {
class: self.class.clone(),
rndr: PhantomData,
}
}
}
impl<C, R> Attribute<R> for Class<C, R>
where
C: IntoClass<R>,
@ -35,6 +44,7 @@ where
type State = C::State;
type Cloneable = Class<C::Cloneable, R>;
type CloneableOwned = Class<C::CloneableOwned, R>;
fn html_len(&self) -> usize {
self.class.html_len() + 1
@ -69,6 +79,13 @@ where
rndr: self.rndr,
}
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
Class {
class: self.class.into_cloneable_owned(),
rndr: self.rndr,
}
}
}
impl<C, R> NextAttribute<R> for Class<C, R>
@ -110,6 +127,7 @@ pub trait IntoClass<R: DomRenderer>: Send {
type State;
type Cloneable: IntoClass<R> + Clone;
type CloneableOwned: IntoClass<R> + Clone + 'static;
fn html_len(&self) -> usize;
@ -125,6 +143,8 @@ pub trait IntoClass<R: DomRenderer>: Send {
fn rebuild(self, state: &mut Self::State);
fn into_cloneable(self) -> Self::Cloneable;
fn into_cloneable_owned(self) -> Self::CloneableOwned;
}
impl<'a, R> IntoClass<R> for &'a str
@ -133,6 +153,7 @@ where
{
type State = (R::Element, Self);
type Cloneable = Self;
type CloneableOwned = Arc<str>;
fn html_len(&self) -> usize {
self.len()
@ -165,6 +186,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.into()
}
}
impl<R> IntoClass<R> for String
@ -173,6 +198,7 @@ where
{
type State = (R::Element, Self);
type Cloneable = Arc<str>;
type CloneableOwned = Arc<str>;
fn html_len(&self) -> usize {
self.len()
@ -205,6 +231,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self.into()
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.into()
}
}
impl<R> IntoClass<R> for Arc<str>
@ -213,6 +243,7 @@ where
{
type State = (R::Element, Self);
type Cloneable = Self;
type CloneableOwned = Self;
fn html_len(&self) -> usize {
self.len()
@ -245,6 +276,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
impl<R> IntoClass<R> for (&'static str, bool)
@ -253,6 +288,7 @@ where
{
type State = (R::ClassList, bool);
type Cloneable = Self;
type CloneableOwned = Self;
fn html_len(&self) -> usize {
self.0.len()
@ -299,6 +335,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::Cloneable {
self
}
}
#[cfg(feature = "nightly")]
@ -311,6 +351,7 @@ where
type State = ();
type Cloneable = Self;
type CloneableOwned = Self;
fn html_len(&self) -> usize {
V.len()
@ -336,6 +377,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
/* #[cfg(test)]

View file

@ -18,16 +18,24 @@ where
}
}
#[derive(Debug, Clone, Copy)]
pub struct InnerHtml<T, R>
where
T: InnerHtmlValue<R>,
R: DomRenderer,
{
#[derive(Debug)]
pub struct InnerHtml<T, R> {
value: T,
rndr: PhantomData<R>,
}
impl<T, R> Clone for InnerHtml<T, R>
where
T: Clone,
{
fn clone(&self) -> Self {
Self {
value: self.value.clone(),
rndr: PhantomData,
}
}
}
impl<T, R> Attribute<R> for InnerHtml<T, R>
where
T: InnerHtmlValue<R>,
@ -37,6 +45,7 @@ where
type State = T::State;
type Cloneable = InnerHtml<T::Cloneable, R>;
type CloneableOwned = InnerHtml<T::CloneableOwned, R>;
fn html_len(&self) -> usize {
self.value.html_len()
@ -73,6 +82,13 @@ where
rndr: self.rndr,
}
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
InnerHtml {
value: self.value.into_cloneable_owned(),
rndr: self.rndr,
}
}
}
impl<T, R> NextAttribute<R> for InnerHtml<T, R>
@ -124,6 +140,7 @@ where
pub trait InnerHtmlValue<R: DomRenderer>: Send {
type State;
type Cloneable: InnerHtmlValue<R> + Clone;
type CloneableOwned: InnerHtmlValue<R> + Clone + 'static;
fn html_len(&self) -> usize;
@ -138,6 +155,8 @@ pub trait InnerHtmlValue<R: DomRenderer>: Send {
fn rebuild(self, state: &mut Self::State);
fn into_cloneable(self) -> Self::Cloneable;
fn into_cloneable_owned(self) -> Self::CloneableOwned;
}
impl<R> InnerHtmlValue<R> for String
@ -146,6 +165,7 @@ where
{
type State = (R::Element, Self);
type Cloneable = Arc<str>;
type CloneableOwned = Arc<str>;
fn html_len(&self) -> usize {
self.len()
@ -182,6 +202,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self.into()
}
fn into_cloneable_owned(self) -> Self::Cloneable {
self.into()
}
}
impl<R> InnerHtmlValue<R> for Arc<str>
@ -190,6 +214,7 @@ where
{
type State = (R::Element, Self);
type Cloneable = Self;
type CloneableOwned = Self;
fn html_len(&self) -> usize {
self.len()
@ -226,6 +251,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::Cloneable {
self
}
}
impl<'a, R> InnerHtmlValue<R> for &'a str
@ -234,6 +263,7 @@ where
{
type State = (R::Element, Self);
type Cloneable = Self;
type CloneableOwned = Arc<str>;
fn html_len(&self) -> usize {
self.len()
@ -270,6 +300,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.into()
}
}
impl<T, R> InnerHtmlValue<R> for Option<T>
@ -279,6 +313,7 @@ where
{
type State = Option<T::State>;
type Cloneable = Option<T::Cloneable>;
type CloneableOwned = Option<T::CloneableOwned>;
fn html_len(&self) -> usize {
match self {
@ -313,4 +348,8 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self.map(|inner| inner.into_cloneable())
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.map(|inner| inner.into_cloneable_owned())
}
}

View file

@ -121,13 +121,6 @@ where
rndr,
}
}
fn add_any_attr_by_ref<NewAttr: Attribute<Rndr>>(
self,
attr: &NewAttr,
) -> Self::Output<NewAttr> {
todo!()
}
}
pub trait ElementChild<Rndr, NewChild>

View file

@ -3,7 +3,6 @@ use crate::{
renderer::{CastFrom, DomRenderer, RemoveEventHandler},
view::{Position, ToTemplate},
};
use or_poisoned::OrPoisoned;
use send_wrapper::SendWrapper;
use std::{
borrow::Cow,
@ -12,10 +11,41 @@ use std::{
marker::PhantomData,
ops::{Deref, DerefMut},
rc::Rc,
sync::{Arc, Mutex},
};
use wasm_bindgen::convert::FromWasmAbi;
pub type SharedEventCallback<E> = Rc<RefCell<dyn FnMut(E)>>;
pub trait EventCallback<E>: 'static {
fn invoke(&mut self, event: E);
fn into_shared(self) -> SharedEventCallback<E>;
}
impl<E: 'static> EventCallback<E> for SharedEventCallback<E> {
fn invoke(&mut self, event: E) {
let mut fun = self.borrow_mut();
fun(event)
}
fn into_shared(self) -> SharedEventCallback<E> {
self
}
}
impl<F, E> EventCallback<E> for F
where
F: FnMut(E) + 'static,
{
fn invoke(&mut self, event: E) {
self(event)
}
fn into_shared(self) -> SharedEventCallback<E> {
Rc::new(RefCell::new(self))
}
}
pub struct Targeted<E, T, R> {
event: E,
el_ty: PhantomData<T>,
@ -94,16 +124,29 @@ where
on(event, Box::new(move |ev: E::EventType| cb(ev.into())))
}
#[derive(Clone)]
pub struct On<E, F, R> {
event: E,
cb: SendWrapper<F>,
ty: PhantomData<R>,
}
impl<E, F, R> Clone for On<E, F, R>
where
E: Clone,
F: Clone,
{
fn clone(&self) -> Self {
Self {
event: self.event.clone(),
cb: self.cb.clone(),
ty: PhantomData,
}
}
}
impl<E, F, R> On<E, F, R>
where
F: FnMut(E::EventType) + 'static,
F: EventCallback<E::EventType>,
E: EventDescriptor + Send + 'static,
E::EventType: 'static,
R: DomRenderer,
@ -125,7 +168,7 @@ where
let mut cb = self.cb.take();
let cb = Box::new(move |ev: R::Event| {
let ev = E::EventType::from(ev);
cb(ev);
cb.invoke(ev);
}) as Box<dyn FnMut(R::Event)>;
attach_inner::<R>(
@ -150,7 +193,7 @@ where
impl<E, F, R> Attribute<R> for On<E, F, R>
where
F: FnMut(E::EventType) + 'static,
F: EventCallback<E::EventType>,
E: EventDescriptor + Send + 'static,
E::EventType: 'static,
R: DomRenderer,
@ -159,7 +202,8 @@ where
const MIN_LENGTH: usize = 0;
// a function that can be called once to remove the event listener
type State = (R::Element, Option<Box<dyn FnOnce(&R::Element)>>);
type Cloneable = On<E, Arc<dyn FnMut(E::EventType)>, R>;
type Cloneable = On<E, SharedEventCallback<E::EventType>, R>;
type CloneableOwned = On<E, SharedEventCallback<E::EventType>, R>;
#[inline(always)]
fn html_len(&self) -> usize {
@ -198,12 +242,16 @@ where
}
fn into_cloneable(self) -> Self::Cloneable {
let cb = Rc::new(RefCell::new(self.cb));
On {
cb: SendWrapper::new(Arc::new(move |ev| {
let mut cb = cb.borrow_mut();
cb(ev)
})),
cb: SendWrapper::new(self.cb.take().into_shared()),
event: self.event,
ty: self.ty,
}
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
On {
cb: SendWrapper::new(self.cb.take().into_shared()),
event: self.event,
ty: self.ty,
}
@ -212,7 +260,7 @@ where
impl<E, F, R> NextAttribute<R> for On<E, F, R>
where
F: FnMut(E::EventType) + 'static,
F: EventCallback<E::EventType>,
E: EventDescriptor + Send + 'static,
E::EventType: 'static,
R: DomRenderer,

View file

@ -1,9 +1,10 @@
use super::attribute::Attribute;
use crate::{
hydration::Cursor,
prelude::{Render, RenderHtml},
renderer::Renderer,
ssr::StreamBuilder,
view::{Position, PositionState},
view::{add_attr::AddAnyAttr, Position, PositionState},
};
use std::marker::PhantomData;
@ -58,6 +59,34 @@ where
}
}
impl<Rndr, View> AddAnyAttr<Rndr> for Island<Rndr, View>
where
View: RenderHtml<Rndr>,
Rndr: Renderer,
{
type Output<SomeNewAttr: Attribute<Rndr>> =
Island<Rndr, <View as AddAnyAttr<Rndr>>::Output<SomeNewAttr>>;
fn add_any_attr<NewAttr: Attribute<Rndr>>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<Rndr>,
{
let Island {
component,
view,
rndr,
} = self;
Island {
component,
view: view.add_any_attr(attr),
rndr,
}
}
}
impl<Rndr, View> RenderHtml<Rndr> for Island<Rndr, View>
where
View: RenderHtml<Rndr>,
@ -151,6 +180,29 @@ where
fn rebuild(self, _state: &mut Self::State) {}
}
impl<Rndr, View> AddAnyAttr<Rndr> for IslandChildren<Rndr, View>
where
View: RenderHtml<Rndr>,
Rndr: Renderer,
{
type Output<SomeNewAttr: Attribute<Rndr>> =
IslandChildren<Rndr, <View as AddAnyAttr<Rndr>>::Output<SomeNewAttr>>;
fn add_any_attr<NewAttr: Attribute<Rndr>>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<Rndr>,
{
let IslandChildren { view, rndr } = self;
IslandChildren {
view: view.add_any_attr(attr),
rndr,
}
}
}
impl<Rndr, View> RenderHtml<Rndr> for IslandChildren<Rndr, View>
where
View: RenderHtml<Rndr>,

View file

@ -1,6 +1,8 @@
use self::attribute::Attribute;
use crate::{
no_attrs,
renderer::Renderer,
view::{Position, Render, RenderHtml},
view::{add_attr::AddAnyAttr, Position, Render, RenderHtml},
};
use std::marker::PhantomData;
@ -33,6 +35,8 @@ impl<R: Renderer> Render<R> for Doctype<R> {
fn rebuild(self, _state: &mut Self::State) {}
}
no_attrs!(Doctype<R>);
impl<R> RenderHtml<R> for Doctype<R>
where
R: Renderer + Send,

View file

@ -8,7 +8,7 @@ use crate::{
};
use std::marker::PhantomData;
pub trait NodeRefContainer<E, Rndr>: Send
pub trait NodeRefContainer<E, Rndr>: Send + Clone
where
E: ElementType,
Rndr: Renderer,
@ -16,17 +16,26 @@ where
fn load(self, el: &Rndr::Element);
}
pub struct NodeRefAttr<E, C, Rndr>
where
E: ElementType,
C: NodeRefContainer<E, Rndr>,
Rndr: Renderer,
{
#[derive(Debug)]
pub struct NodeRefAttr<E, C, Rndr> {
container: C,
ty: PhantomData<E>,
rndr: PhantomData<Rndr>,
}
impl<E, C, Rndr> Clone for NodeRefAttr<E, C, Rndr>
where
C: Clone,
{
fn clone(&self) -> Self {
Self {
container: self.container.clone(),
ty: PhantomData,
rndr: PhantomData,
}
}
}
pub fn node_ref<E, C, Rndr>(container: C) -> NodeRefAttr<E, C, Rndr>
where
E: ElementType,
@ -49,7 +58,8 @@ where
{
const MIN_LENGTH: usize = 0;
type State = ();
type Cloneable = Self;
type Cloneable = ();
type CloneableOwned = ();
#[inline(always)]
fn html_len(&self) -> usize {
@ -81,6 +91,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
panic!("node_ref should not be spread across multiple elements.");
}
fn into_cloneable_owned(self) -> Self::Cloneable {
panic!("node_ref should not be spread across multiple elements.");
}
}
impl<E, C, Rndr> NextAttribute<Rndr> for NodeRefAttr<E, C, Rndr>

View file

@ -4,7 +4,7 @@ use crate::{
view::{Position, ToTemplate},
};
use send_wrapper::SendWrapper;
use std::{marker::PhantomData, sync::Arc};
use std::{borrow::Cow, marker::PhantomData, sync::Arc};
use wasm_bindgen::JsValue;
#[inline(always)]
@ -21,18 +21,28 @@ where
}
}
pub struct Property<K, P, R>
where
K: AsRef<str>,
P: IntoProperty<R>,
R: DomRenderer,
{
#[derive(Debug)]
pub struct Property<K, P, R> {
key: K,
// property values will only be accessed in the browser
value: SendWrapper<P>,
rndr: PhantomData<R>,
}
impl<K, P, R> Clone for Property<K, P, R>
where
K: Clone,
P: Clone,
{
fn clone(&self) -> Self {
Self {
key: self.key.clone(),
value: self.value.clone(),
rndr: PhantomData,
}
}
}
impl<K, P, R> Attribute<R> for Property<K, P, R>
where
K: AsRef<str> + Send,
@ -43,6 +53,7 @@ where
type State = P::State;
type Cloneable = Property<Arc<str>, P::Cloneable, R>;
type CloneableOwned = Property<Arc<str>, P::CloneableOwned, R>;
#[inline(always)]
fn html_len(&self) -> usize {
@ -79,6 +90,14 @@ where
rndr: self.rndr,
}
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
Property {
key: self.key.as_ref().into(),
value: SendWrapper::new(self.value.take().into_cloneable_owned()),
rndr: self.rndr,
}
}
}
impl<K, P, R> NextAttribute<R> for Property<K, P, R>
@ -116,6 +135,7 @@ where
pub trait IntoProperty<R: DomRenderer> {
type State;
type Cloneable: IntoProperty<R> + Clone;
type CloneableOwned: IntoProperty<R> + Clone + 'static;
fn hydrate<const FROM_SERVER: bool>(
self,
@ -128,6 +148,8 @@ pub trait IntoProperty<R: DomRenderer> {
fn rebuild(self, state: &mut Self::State, key: &str);
fn into_cloneable(self) -> Self::Cloneable;
fn into_cloneable_owned(self) -> Self::CloneableOwned;
}
macro_rules! prop_type {
@ -138,6 +160,7 @@ macro_rules! prop_type {
{
type State = (R::Element, JsValue);
type Cloneable = Self;
type CloneableOwned = Self;
fn hydrate<const FROM_SERVER: bool>(
self,
@ -167,6 +190,10 @@ macro_rules! prop_type {
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
impl<R> IntoProperty<R> for Option<$prop_type>
@ -175,6 +202,7 @@ macro_rules! prop_type {
{
type State = (R::Element, JsValue);
type Cloneable = Self;
type CloneableOwned = Self;
fn hydrate<const FROM_SERVER: bool>(
self,
@ -210,14 +238,207 @@ macro_rules! prop_type {
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
};
}
macro_rules! prop_type_str {
($prop_type:ty) => {
impl<R> IntoProperty<R> for $prop_type
where
R: DomRenderer,
{
type State = (R::Element, JsValue);
type Cloneable = Arc<str>;
type CloneableOwned = Arc<str>;
fn hydrate<const FROM_SERVER: bool>(
self,
el: &R::Element,
key: &str,
) -> Self::State {
let value = JsValue::from(&*self);
R::set_property(el, key, &value);
(el.clone(), value)
}
fn build(self, el: &R::Element, key: &str) -> Self::State {
let value = JsValue::from(&*self);
R::set_property(el, key, &value);
(el.clone(), value)
}
fn rebuild(self, state: &mut Self::State, key: &str) {
let (el, prev) = state;
let value = JsValue::from(&*self);
if value != *prev {
R::set_property(el, key, &value);
}
*prev = value;
}
fn into_cloneable(self) -> Self::Cloneable {
let this: &str = &*self;
this.into()
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
let this: &str = &*self;
this.into()
}
}
impl<R> IntoProperty<R> for Option<$prop_type>
where
R: DomRenderer,
{
type State = (R::Element, JsValue);
type Cloneable = Option<Arc<str>>;
type CloneableOwned = Option<Arc<str>>;
fn hydrate<const FROM_SERVER: bool>(
self,
el: &R::Element,
key: &str,
) -> Self::State {
let was_some = self.is_some();
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
if was_some {
R::set_property(el, key, &value);
}
(el.clone(), value)
}
fn build(self, el: &R::Element, key: &str) -> Self::State {
let was_some = self.is_some();
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
if was_some {
R::set_property(el, key, &value);
}
(el.clone(), value)
}
fn rebuild(self, state: &mut Self::State, key: &str) {
let (el, prev) = state;
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
if value != *prev {
R::set_property(el, key, &value);
}
*prev = value;
}
fn into_cloneable(self) -> Self::Cloneable {
self.map(|n| {
let this: &str = &*n;
this.into()
})
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.map(|n| {
let this: &str = &*n;
this.into()
})
}
}
};
}
impl<R> IntoProperty<R> for Arc<str>
where
R: DomRenderer,
{
type State = (R::Element, JsValue);
type Cloneable = Self;
type CloneableOwned = Self;
fn hydrate<const FROM_SERVER: bool>(
self,
el: &R::Element,
key: &str,
) -> Self::State {
let value = JsValue::from_str(self.as_ref());
R::set_property(el, key, &value);
(el.clone(), value)
}
fn build(self, el: &R::Element, key: &str) -> Self::State {
let value = JsValue::from_str(self.as_ref());
R::set_property(el, key, &value);
(el.clone(), value)
}
fn rebuild(self, state: &mut Self::State, key: &str) {
let (el, prev) = state;
let value = JsValue::from_str(self.as_ref());
if value != *prev {
R::set_property(el, key, &value);
}
*prev = value;
}
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
impl<R> IntoProperty<R> for Option<Arc<str>>
where
R: DomRenderer,
{
type State = (R::Element, JsValue);
type Cloneable = Self;
type CloneableOwned = Self;
fn hydrate<const FROM_SERVER: bool>(
self,
el: &R::Element,
key: &str,
) -> Self::State {
let was_some = self.is_some();
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
if was_some {
R::set_property(el, key, &value);
}
(el.clone(), value)
}
fn build(self, el: &R::Element, key: &str) -> Self::State {
let was_some = self.is_some();
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
if was_some {
R::set_property(el, key, &value);
}
(el.clone(), value)
}
fn rebuild(self, state: &mut Self::State, key: &str) {
let (el, prev) = state;
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
if value != *prev {
R::set_property(el, key, &value);
}
*prev = value;
}
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
prop_type!(JsValue);
prop_type!(String);
prop_type!(&String);
prop_type!(&str);
prop_type!(usize);
prop_type!(u8);
prop_type!(u16);
@ -233,3 +454,8 @@ prop_type!(i128);
prop_type!(f32);
prop_type!(f64);
prop_type!(bool);
prop_type_str!(String);
prop_type_str!(&String);
prop_type_str!(&str);
prop_type_str!(Cow<'_, str>);

View file

@ -20,15 +20,24 @@ where
}
}
pub struct Style<S, R>
where
S: IntoStyle<R>,
R: DomRenderer,
{
#[derive(Debug)]
pub struct Style<S, R> {
style: S,
rndr: PhantomData<R>,
}
impl<S, R> Clone for Style<S, R>
where
S: Clone,
{
fn clone(&self) -> Self {
Self {
style: self.style.clone(),
rndr: PhantomData,
}
}
}
impl<S, R> Attribute<R> for Style<S, R>
where
S: IntoStyle<R>,
@ -38,6 +47,7 @@ where
type State = S::State;
type Cloneable = Style<S::Cloneable, R>;
type CloneableOwned = Style<S::CloneableOwned, R>;
// TODO
#[inline(always)]
@ -73,6 +83,13 @@ where
rndr: self.rndr,
}
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
Style {
style: self.style.into_cloneable_owned(),
rndr: self.rndr,
}
}
}
impl<S, R> NextAttribute<R> for Style<S, R>
@ -111,6 +128,7 @@ where
pub trait IntoStyle<R: DomRenderer>: Send {
type State;
type Cloneable: IntoStyle<R> + Clone;
type CloneableOwned: IntoStyle<R> + Clone + 'static;
fn to_html(self, style: &mut String);
@ -121,6 +139,8 @@ pub trait IntoStyle<R: DomRenderer>: Send {
fn rebuild(self, state: &mut Self::State);
fn into_cloneable(self) -> Self::Cloneable;
fn into_cloneable_owned(self) -> Self::CloneableOwned;
}
pub trait StylePropertyValue<R: DomRenderer> {
@ -143,6 +163,7 @@ where
{
type State = (R::Element, &'a str);
type Cloneable = Self;
type CloneableOwned = Arc<str>;
fn to_html(self, style: &mut String) {
style.push_str(self);
@ -169,14 +190,19 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.into()
}
}
impl<R> IntoStyle<R> for String
impl<R> IntoStyle<R> for Arc<str>
where
R: DomRenderer,
{
type State = (R::Element, String);
type Cloneable = String; // TODO can do Arc<str> here I guess
type State = (R::Element, Arc<str>);
type Cloneable = Self;
type CloneableOwned = Self;
fn to_html(self, style: &mut String) {
style.push_str(&self);
@ -203,6 +229,95 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
impl<R> IntoStyle<R> for String
where
R: DomRenderer,
{
type State = (R::Element, String);
type Cloneable = Arc<str>;
type CloneableOwned = Arc<str>;
fn to_html(self, style: &mut String) {
style.push_str(&self);
style.push(';');
}
fn hydrate<const FROM_SERVER: bool>(self, el: &R::Element) -> Self::State {
(el.clone(), self)
}
fn build(self, el: &R::Element) -> Self::State {
R::set_attribute(el, "style", &self);
(el.clone(), self)
}
fn rebuild(self, state: &mut Self::State) {
let (el, prev) = state;
if self != *prev {
R::set_attribute(el, "style", &self);
}
*prev = self;
}
fn into_cloneable(self) -> Self::Cloneable {
self.into()
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.into()
}
}
impl<R> IntoStyle<R> for (Arc<str>, Arc<str>)
where
R: DomRenderer,
{
type State = (R::CssStyleDeclaration, Arc<str>);
type Cloneable = Self;
type CloneableOwned = Self;
fn to_html(self, style: &mut String) {
let (name, value) = self;
style.push_str(&name);
style.push(':');
style.push_str(&value);
style.push(';');
}
fn hydrate<const FROM_SERVER: bool>(self, el: &R::Element) -> Self::State {
let style = R::style(el);
(style, self.1)
}
fn build(self, el: &R::Element) -> Self::State {
let (name, value) = self;
let style = R::style(el);
R::set_css_property(&style, &name, &value);
(style, value)
}
fn rebuild(self, state: &mut Self::State) {
let (name, value) = self;
let (style, prev) = state;
if value != *prev {
R::set_css_property(style, &name, &value);
}
*prev = value;
}
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::Cloneable {
self
}
}
impl<'a, R> IntoStyle<R> for (&'a str, &'a str)
@ -211,6 +326,7 @@ where
{
type State = (R::CssStyleDeclaration, &'a str);
type Cloneable = Self;
type CloneableOwned = (Arc<str>, Arc<str>);
fn to_html(self, style: &mut String) {
let (name, value) = self;
@ -244,6 +360,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
(self.0.into(), self.1.into())
}
}
impl<'a, R> IntoStyle<R> for (&'a str, String)
@ -251,7 +371,8 @@ where
R: DomRenderer,
{
type State = (R::CssStyleDeclaration, String);
type Cloneable = Self; // TODO can use Arc<str> here
type Cloneable = (Arc<str>, Arc<str>);
type CloneableOwned = (Arc<str>, Arc<str>);
fn to_html(self, style: &mut String) {
let (name, value) = self;
@ -283,7 +404,11 @@ where
}
fn into_cloneable(self) -> Self::Cloneable {
self
(self.0.into(), self.1.into())
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
(self.0.into(), self.1.into())
}
}
@ -295,6 +420,7 @@ where
{
type State = ();
type Cloneable = Self;
type CloneableOwned = Self;
fn to_html(self, style: &mut String) {
style.push_str(V);
@ -316,6 +442,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
/*

View file

@ -1,9 +1,13 @@
use crate::{
html::{attribute::AttributeValue, class::IntoClass},
hydration::Cursor,
no_attrs,
prelude::{Mountable, Render, RenderHtml},
renderer::{DomRenderer, Renderer},
view::{strings::StrState, Position, PositionState, ToTemplate},
view::{
add_attr::AddAnyAttr, strings::StrState, Position, PositionState,
ToTemplate,
},
};
use oco_ref::Oco;
@ -29,6 +33,8 @@ impl<R: Renderer> Render<R> for Oco<'static, str> {
}
}
no_attrs!(Oco<'static, str>);
impl<R> RenderHtml<R> for Oco<'static, str>
where
R: Renderer,

View file

@ -16,6 +16,7 @@ where
{
type State = RenderEffectState<C::State>;
type Cloneable = SharedReactiveFunction<C>;
type CloneableOwned = SharedReactiveFunction<C>;
fn html_len(&self) -> usize {
0
@ -80,6 +81,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self.into_shared()
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.into_shared()
}
}
impl<F, T, R> IntoClass<R> for (&'static str, F)
@ -90,6 +95,7 @@ where
{
type State = RenderEffectState<(R::ClassList, bool)>;
type Cloneable = (&'static str, SharedReactiveFunction<T>);
type CloneableOwned = (&'static str, SharedReactiveFunction<T>);
fn html_len(&self) -> usize {
self.0.len()
@ -160,6 +166,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
(self.0, self.1.into_shared())
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
(self.0, self.1.into_shared())
}
}
impl<F, T, R> IntoClass<R> for (Vec<Cow<'static, str>>, F)
@ -170,6 +180,7 @@ where
{
type State = RenderEffectState<(R::ClassList, bool)>;
type Cloneable = (Vec<Cow<'static, str>>, SharedReactiveFunction<T>);
type CloneableOwned = (Vec<Cow<'static, str>>, SharedReactiveFunction<T>);
fn html_len(&self) -> usize {
self.0.iter().map(|n| n.len()).sum()
@ -251,6 +262,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
(self.0.clone(), self.1.into_shared())
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
(self.0.clone(), self.1.into_shared())
}
}
impl<G, R> IntoClass<R> for ReadGuard<String, G>
@ -260,6 +275,7 @@ where
{
type State = <String as IntoClass<R>>::State;
type Cloneable = Arc<str>;
type CloneableOwned = Arc<str>;
fn html_len(&self) -> usize {
self.len()
@ -290,6 +306,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self.as_str().into()
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.as_str().into()
}
}
impl<G, R> IntoClass<R> for (&'static str, ReadGuard<bool, G>)
@ -299,6 +319,7 @@ where
{
type State = <(&'static str, bool) as IntoClass<R>>::State;
type Cloneable = (&'static str, bool);
type CloneableOwned = (&'static str, bool);
fn html_len(&self) -> usize {
self.0.len()
@ -338,6 +359,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
(self.0, *self.1)
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
(self.0, *self.1)
}
}
#[cfg(not(feature = "nightly"))]

View file

@ -1,12 +1,13 @@
//! Implements the [`Render`] and [`RenderHtml`] traits for signal guard types.
use crate::{
html::attribute::Attribute,
hydration::Cursor,
prelude::RenderHtml,
renderer::{CastFrom, Renderer},
view::{
strings::StrState, Mountable, Position, PositionState, Render,
ToTemplate,
add_attr::AddAnyAttr, strings::StrState, Mountable, Position,
PositionState, Render, ToTemplate,
},
};
use reactive_graph::signal::guards::ReadGuard;
@ -72,6 +73,26 @@ macro_rules! render_primitive {
}
}
impl<G, R> AddAnyAttr<R> for ReadGuard<$child_type, G>
where
R: Renderer,
G: Deref<Target = $child_type> + Send
{
type Output<SomeNewAttr: Attribute<R>> = ReadGuard<$child_type, G>;
fn add_any_attr<NewAttr: Attribute<R>>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<R>,
{
// TODO: there is a strange compiler thing that seems to prevent us returning Self here,
// even though we've already said that Output is always the same as Self
todo!()
}
}
impl<G, R> RenderHtml<R> for ReadGuard<$child_type, G>
where
R: Renderer,
@ -218,10 +239,29 @@ where
}
}
impl<G, R> AddAnyAttr<R> for ReadGuard<String, G>
where
G: Deref<Target = String> + Send,
R: Renderer,
{
type Output<SomeNewAttr: Attribute<R>> = ReadGuard<String, G>;
fn add_any_attr<NewAttr: Attribute<R>>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<R>,
{
// TODO: there is a strange compiler thing that seems to prevent us returning Self here,
// even though we've already said that Output is always the same as Self
todo!()
}
}
impl<G, R> RenderHtml<R> for ReadGuard<String, G>
where
R: Renderer,
G: Deref<Target = String> + Send,
{
type AsyncOutput = Self;

View file

@ -14,6 +14,7 @@ where
{
type State = RenderEffect<V::State>;
type Cloneable = SharedReactiveFunction<V>;
type CloneableOwned = SharedReactiveFunction<V>;
fn html_len(&self) -> usize {
0
@ -60,6 +61,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self.into_shared()
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.into_shared()
}
}
#[cfg(not(feature = "nightly"))]

View file

@ -23,7 +23,7 @@ pub use owned::*;
impl<F, V> ToTemplate for F
where
F: FnMut() -> V,
F: ReactiveFunction<Output = V>,
V: ToTemplate,
{
const TEMPLATE: &'static str = V::TEMPLATE;
@ -42,7 +42,7 @@ where
impl<F, V, R> Render<R> for F
where
F: FnMut() -> V + 'static,
F: ReactiveFunction<Output = V>,
V: Render<R>,
V::State: 'static,
R: Renderer,
@ -52,7 +52,7 @@ where
#[track_caller]
fn build(mut self) -> Self::State {
RenderEffect::new(move |prev| {
let value = self();
let value = self.invoke();
if let Some(mut state) = prev {
value.rebuild(&mut state);
state
@ -146,7 +146,7 @@ where
impl<F, V, R> RenderHtml<R> for F
where
F: FnMut() -> V + Send + 'static,
F: ReactiveFunction<Output = V>,
V: RenderHtml<R>,
V::State: 'static,
@ -157,7 +157,7 @@ where
const MIN_LENGTH: usize = 0;
async fn resolve(mut self) -> Self::AsyncOutput {
self().resolve().await
self.invoke().resolve().await
}
fn html_len(&self) -> usize {
@ -165,7 +165,7 @@ where
}
fn to_html_with_buf(mut self, buf: &mut String, position: &mut Position) {
let value = self();
let value = self.invoke();
value.to_html_with_buf(buf, position)
}
@ -176,7 +176,7 @@ where
) where
Self: Sized,
{
let value = self();
let value = self.invoke();
value.to_html_async_with_buf::<OUT_OF_ORDER>(buf, position);
}
@ -188,7 +188,7 @@ where
let cursor = cursor.clone();
let position = position.clone();
RenderEffect::new(move |prev| {
let value = self();
let value = self.invoke();
if let Some(mut state) = prev {
value.rebuild(&mut state);
state
@ -202,13 +202,12 @@ where
impl<F, V, R> AddAnyAttr<R> for F
where
F: FnMut() -> V + Send + 'static,
V: RenderHtml<R>,
V::State: 'static,
F: ReactiveFunction<Output = V>,
V: AddAnyAttr<R>,
R: Renderer + 'static,
{
type Output<SomeNewAttr: Attribute<R>> = Self;
type Output<SomeNewAttr: Attribute<R>> =
SharedReactiveFunction<V::Output<SomeNewAttr>>;
fn add_any_attr<NewAttr: Attribute<R>>(
self,
@ -217,17 +216,9 @@ where
where
Self::Output<NewAttr>: RenderHtml<R>,
{
self
}
fn add_any_attr_by_ref<NewAttr: Attribute<R>>(
self,
attr: &NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<R>,
{
self
/*let attr = attr.into_cloneable_owned();
Arc::new(Mutex::new(move || self.invoke().add_any_attr(attr.clone())));*/
todo!()
}
}
@ -304,6 +295,7 @@ where
{
type State = RenderEffectState<V::State>;
type Cloneable = SharedReactiveFunction<V>;
type CloneableOwned = SharedReactiveFunction<V>;
fn html_len(&self) -> usize {
0
@ -365,6 +357,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self.into_shared()
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.into_shared()
}
}
pub type SharedReactiveFunction<T> = Arc<Mutex<dyn FnMut() -> T + Send>>;

View file

@ -1,9 +1,10 @@
use crate::{
html::attribute::Attribute,
hydration::Cursor,
prelude::Mountable,
renderer::Renderer,
ssr::StreamBuilder,
view::{Position, PositionState, Render, RenderHtml},
view::{add_attr::AddAnyAttr, Position, PositionState, Render, RenderHtml},
};
use reactive_graph::owner::Owner;
use std::marker::PhantomData;
@ -81,6 +82,30 @@ where
}
}
impl<T, R> AddAnyAttr<R> for OwnedView<T, R>
where
T: AddAnyAttr<R>,
R: Renderer,
{
type Output<SomeNewAttr: Attribute<R>> =
OwnedView<T::Output<SomeNewAttr>, R>;
fn add_any_attr<NewAttr: Attribute<R>>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<R>,
{
let OwnedView { owner, view, rndr } = self;
OwnedView {
owner,
view: view.add_any_attr(attr),
rndr,
}
}
}
impl<T, R> RenderHtml<R> for OwnedView<T, R>
where
T: RenderHtml<R>,

View file

@ -15,6 +15,7 @@ where
{
type State = RenderEffect<V::State>;
type Cloneable = SharedReactiveFunction<V>;
type CloneableOwned = SharedReactiveFunction<V>;
fn hydrate<const FROM_SERVER: bool>(
mut self,
@ -63,6 +64,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self.into_shared()
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.into_shared()
}
}
#[cfg(not(feature = "nightly"))]

View file

@ -15,6 +15,7 @@ where
{
type State = RenderEffect<(R::CssStyleDeclaration, Cow<'static, str>)>;
type Cloneable = (&'static str, SharedReactiveFunction<S>);
type CloneableOwned = (&'static str, SharedReactiveFunction<S>);
fn to_html(self, style: &mut String) {
let (name, mut f) = self;
@ -84,6 +85,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
(self.0, self.1.into_shared())
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
(self.0, self.1.into_shared())
}
}
impl<F, C, R> IntoStyle<R> for F
@ -95,6 +100,7 @@ where
{
type State = RenderEffect<C::State>;
type Cloneable = SharedReactiveFunction<C>;
type CloneableOwned = SharedReactiveFunction<C>;
fn to_html(mut self, style: &mut String) {
let value = self.invoke();
@ -136,6 +142,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self.into_shared()
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.into_shared()
}
}
#[cfg(not(feature = "nightly"))]
@ -150,6 +160,7 @@ mod stable {
{
type State = RenderEffect<C::State>;
type Cloneable = Self;
type CloneableOwned = Self;
fn to_html(self, style: &mut String) {
let value = self.get();
@ -174,6 +185,10 @@ mod stable {
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
impl<R, S> IntoStyle<R> for (&'static str, $sig<S>)
@ -184,6 +199,7 @@ mod stable {
type State =
RenderEffect<(R::CssStyleDeclaration, Cow<'static, str>)>;
type Cloneable = Self;
type CloneableOwned = Self;
fn to_html(self, style: &mut String) {
IntoStyle::<R>::to_html(
@ -213,6 +229,10 @@ mod stable {
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
};
}
@ -227,6 +247,7 @@ mod stable {
{
type State = RenderEffect<C::State>;
type Cloneable = Self;
type CloneableOwned = Self;
fn to_html(self, style: &mut String) {
let value = self.get();
@ -251,6 +272,10 @@ mod stable {
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
impl<R, S> IntoStyle<R> for (&'static str, $sig<S>)
@ -261,6 +286,7 @@ mod stable {
type State =
RenderEffect<(R::CssStyleDeclaration, Cow<'static, str>)>;
type Cloneable = Self;
type CloneableOwned = Self;
fn to_html(self, style: &mut String) {
IntoStyle::<R>::to_html(
@ -290,6 +316,10 @@ mod stable {
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
};
}

View file

@ -15,7 +15,7 @@ pub mod sledgehammer;
/// By default, this is implemented for the Document Object Model (DOM) in a Web
/// browser, but implementing this trait for some other platform allows you to use
/// the library to render any tree-based UI.
pub trait Renderer: Send + Sized + Debug {
pub trait Renderer: Send + Sized + Debug + 'static {
/// The basic type of node in the view tree.
type Node: Mountable<Self> + Clone + 'static;
/// A visible element in the view tree.

View file

@ -20,11 +20,24 @@ where
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<Rndr>;
fn add_any_attr_by_ref<NewAttr: Attribute<Rndr>>(
self,
attr: &NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<Rndr>;
}
#[macro_export]
macro_rules! no_attrs {
($ty_name:ty) => {
impl<'a, R> crate::view::add_attr::AddAnyAttr<R> for $ty_name
where
R: Renderer,
{
type Output<SomeNewAttr: crate::html::attribute::Attribute<R>> =
$ty_name;
fn add_any_attr<NewAttr: crate::html::attribute::Attribute<R>>(
self,
_attr: NewAttr,
) -> Self::Output<NewAttr> {
self
}
}
};
}

View file

@ -1,5 +1,11 @@
use super::{Mountable, Position, PositionState, Render, RenderHtml};
use crate::{hydration::Cursor, renderer::Renderer, ssr::StreamBuilder};
use super::{
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
RenderHtml,
};
use crate::{
html::attribute::Attribute, hydration::Cursor, renderer::Renderer,
ssr::StreamBuilder,
};
use std::{
any::{Any, TypeId},
fmt::Debug,
@ -246,6 +252,23 @@ where
}
}
impl<R> AddAnyAttr<R> for AnyView<R>
where
R: Renderer + 'static,
{
type Output<SomeNewAttr: Attribute<R>> = Self;
fn add_any_attr<NewAttr: Attribute<R>>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<R>,
{
todo!()
}
}
impl<R> RenderHtml<R> for AnyView<R>
where
R: Renderer + 'static,

View file

@ -1,5 +1,11 @@
use super::{Mountable, Position, PositionState, Render, RenderHtml};
use crate::{hydration::Cursor, renderer::Renderer, ssr::StreamBuilder};
use super::{
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
RenderHtml,
};
use crate::{
html::attribute::Attribute, hydration::Cursor, renderer::Renderer,
ssr::StreamBuilder,
};
use either_of::*;
pub struct EitherState<A, B, Rndr>
@ -97,6 +103,31 @@ where
}
}
impl<A, B, Rndr> AddAnyAttr<Rndr> for Either<A, B>
where
A: RenderHtml<Rndr>,
B: RenderHtml<Rndr>,
Rndr: Renderer,
{
type Output<SomeNewAttr: Attribute<Rndr>> = Either<
<A as AddAnyAttr<Rndr>>::Output<SomeNewAttr>,
<B as AddAnyAttr<Rndr>>::Output<SomeNewAttr>,
>;
fn add_any_attr<NewAttr: Attribute<Rndr>>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<Rndr>,
{
match self {
Either::Left(i) => Either::Left(i.add_any_attr(attr)),
Either::Right(i) => Either::Right(i.add_any_attr(attr)),
}
}
}
const fn max_usize(vals: &[usize]) -> usize {
let mut max = 0;
let len = vals.len();
@ -261,6 +292,28 @@ where
}
}
impl<A, B, Rndr> AddAnyAttr<Rndr> for EitherKeepAlive<A, B>
where
A: RenderHtml<Rndr>,
B: RenderHtml<Rndr>,
Rndr: Renderer,
{
type Output<SomeNewAttr: Attribute<Rndr>> = EitherKeepAlive<
<A as AddAnyAttr<Rndr>>::Output<SomeNewAttr>,
<B as AddAnyAttr<Rndr>>::Output<SomeNewAttr>,
>;
fn add_any_attr<NewAttr: Attribute<Rndr>>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<Rndr>,
{
todo!()
}
}
impl<A, B, Rndr> RenderHtml<Rndr> for EitherKeepAlive<A, B>
where
A: RenderHtml<Rndr>,
@ -449,6 +502,28 @@ macro_rules! tuples {
}
}
impl<Rndr, $($ty,)*> AddAnyAttr<Rndr> for [<EitherOf $num>]<$($ty,)*>
where
$($ty: RenderHtml<Rndr>,)*
Rndr: Renderer,
{
type Output<SomeNewAttr: Attribute<Rndr>> = [<EitherOf $num>]<
$(<$ty as AddAnyAttr<Rndr>>::Output<SomeNewAttr>,)*
>;
fn add_any_attr<NewAttr: Attribute<Rndr>>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<Rndr>,
{
match self {
$([<EitherOf $num>]::$ty(this) => [<EitherOf $num>]::$ty(this.add_any_attr(attr)),)*
}
}
}
impl<Rndr, $($ty,)*> RenderHtml<Rndr> for [<EitherOf $num>]<$($ty,)*>
where
$($ty: RenderHtml<Rndr>,)*

View file

@ -1,5 +1,6 @@
use super::{Position, PositionState, RenderHtml};
use super::{add_attr::AddAnyAttr, Position, PositionState, RenderHtml};
use crate::{
html::attribute::Attribute,
hydration::Cursor,
ssr::StreamBuilder,
view::{Mountable, Render, Renderer},
@ -112,6 +113,26 @@ where
}
}
impl<R, T, E> AddAnyAttr<R> for Result<T, E>
where
T: AddAnyAttr<R>,
R: Renderer,
E: Into<AnyError> + Send + 'static,
{
type Output<SomeNewAttr: Attribute<R>> =
Result<<T as AddAnyAttr<R>>::Output<SomeNewAttr>, E>;
fn add_any_attr<NewAttr: Attribute<R>>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<R>,
{
todo!()
}
}
impl<R, T, E> RenderHtml<R> for Result<T, E>
where
T: RenderHtml<R>,

View file

@ -1,5 +1,11 @@
use super::{Mountable, Position, PositionState, Render, RenderHtml};
use crate::{hydration::Cursor, renderer::Renderer, ssr::StreamBuilder};
use super::{
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
RenderHtml,
};
use crate::{
html::attribute::Attribute, hydration::Cursor, renderer::Renderer,
ssr::StreamBuilder,
};
use itertools::Itertools;
impl<T, R> Render<R> for Option<T>
@ -39,6 +45,25 @@ where
}
}
impl<T, R> AddAnyAttr<R> for Option<T>
where
T: AddAnyAttr<R>,
R: Renderer,
{
type Output<SomeNewAttr: Attribute<R>> =
Option<<T as AddAnyAttr<R>>::Output<SomeNewAttr>>;
fn add_any_attr<NewAttr: Attribute<R>>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<R>,
{
self.map(|n| n.add_any_attr(attr))
}
}
impl<T, R> RenderHtml<R> for Option<T>
where
T: RenderHtml<R>,
@ -250,6 +275,28 @@ where
}
}
impl<T, R> AddAnyAttr<R> for Vec<T>
where
T: AddAnyAttr<R>,
R: Renderer,
{
type Output<SomeNewAttr: Attribute<R>> =
Vec<<T as AddAnyAttr<R>>::Output<SomeNewAttr::Cloneable>>;
fn add_any_attr<NewAttr: Attribute<R>>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<R>,
{
let attr = attr.into_cloneable();
self.into_iter()
.map(|n| n.add_any_attr(attr.clone()))
.collect()
}
}
impl<T, R> RenderHtml<R> for Vec<T>
where
T: RenderHtml<R>,

View file

@ -1,5 +1,9 @@
use super::{Mountable, Position, PositionState, Render, RenderHtml};
use super::{
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
RenderHtml,
};
use crate::{
html::attribute::Attribute,
hydration::Cursor,
renderer::{CastFrom, Renderer},
ssr::StreamBuilder,
@ -40,7 +44,6 @@ where
I: IntoIterator<Item = T>,
K: Eq + Hash + 'static,
KF: Fn(&T) -> K,
V: Render<Rndr>,
VF: Fn(T) -> V,
Rndr: Renderer,
{
@ -128,14 +131,68 @@ where
}
}
impl<T, I, K, KF, VF, V, Rndr> RenderHtml<Rndr>
impl<T, I, K, KF, VF, V, Rndr> AddAnyAttr<Rndr>
for Keyed<T, I, K, KF, VF, V, Rndr>
where
I: IntoIterator<Item = T> + Send,
K: Eq + Hash + 'static,
KF: Fn(&T) -> K + Send,
V: RenderHtml<Rndr>,
VF: Fn(T) -> V + Send,
V: 'static,
VF: Fn(T) -> V + Send + 'static,
T: 'static,
Rndr: Renderer,
{
type Output<SomeNewAttr: Attribute<Rndr>> = Keyed<
T,
I,
K,
KF,
Box<
dyn Fn(
T,
) -> <V as AddAnyAttr<Rndr>>::Output<
SomeNewAttr::CloneableOwned,
> + Send,
>,
V::Output<SomeNewAttr::CloneableOwned>,
Rndr,
>;
fn add_any_attr<NewAttr: Attribute<Rndr>>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<Rndr>,
{
let Keyed {
items,
key_fn,
view_fn,
rndr,
} = self;
let attr = attr.into_cloneable_owned();
Keyed {
items,
key_fn,
view_fn: Box::new(move |item| {
view_fn(item).add_any_attr(attr.clone())
}),
rndr,
}
}
}
impl<T, I, K, KF, VF, V, Rndr> RenderHtml<Rndr>
for Keyed<T, I, K, KF, VF, V, Rndr>
where
I: IntoIterator<Item = T> + Send,
K: Eq + Hash + 'static,
KF: Fn(&T) -> K + Send,
V: RenderHtml<Rndr> + 'static,
VF: Fn(T) -> V + Send + 'static,
T: 'static,
Rndr: Renderer,
{
type AsyncOutput = Vec<V::AsyncOutput>; // TODO

View file

@ -1,3 +1,4 @@
use self::add_attr::AddAnyAttr;
use crate::{hydration::Cursor, renderer::Renderer, ssr::StreamBuilder};
use parking_lot::RwLock;
use std::{future::Future, sync::Arc};
@ -19,6 +20,12 @@ pub mod tuples;
///
/// It is generic over the renderer itself, as long as that implements the [`Renderer`]
/// trait.
#[diagnostic::on_unimplemented(
message = "`Render<{R}>` is not implemented for `{Self}`",
label = "My Label",
note = "Note 1",
note = "Note 2"
)]
pub trait Render<R: Renderer>: Sized {
/// The “view state” for this type, which can be retained between updates.
///
@ -58,7 +65,7 @@ impl std::error::Error for NeverError {}
/// whole view piece by piece.
pub trait RenderHtml<R: Renderer>
where
Self: Render<R> + Send,
Self: Render<R> + AddAnyAttr<R> + Send,
{
/// The type of the view after waiting for all asynchronous data to load.
type AsyncOutput: RenderHtml<R>;

View file

@ -1,6 +1,7 @@
use super::{Mountable, Position, PositionState, Render, RenderHtml};
use crate::{
hydration::Cursor,
no_attrs,
renderer::{CastFrom, Renderer},
view::ToTemplate,
};
@ -62,6 +63,8 @@ macro_rules! render_primitive {
}
}
no_attrs!($child_type);
impl<R> RenderHtml<R> for $child_type
where
R: Renderer,

View file

@ -1,5 +1,6 @@
use super::{
Mountable, Position, PositionState, Render, RenderHtml, ToTemplate,
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
RenderHtml, ToTemplate,
};
use crate::{
html::attribute::{Attribute, AttributeKey, AttributeValue, NextAttribute},
@ -28,6 +29,12 @@ pub struct StaticAttr<K: AttributeKey, const V: &'static str> {
ty: PhantomData<K>,
}
impl<K: AttributeKey, const V: &'static str> Clone for StaticAttr<K, V> {
fn clone(&self) -> Self {
Self { ty: PhantomData }
}
}
impl<K: AttributeKey, const V: &'static str> PartialEq for StaticAttr<K, V> {
fn eq(&self, _other: &Self) -> bool {
// by definition, two static attrs with same key and same const V are same
@ -68,6 +75,7 @@ where
type State = ();
type Cloneable = Self;
type CloneableOwned = Self;
#[inline(always)]
fn html_len(&self) -> usize {
@ -96,6 +104,10 @@ where
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self
}
}
impl<K, const V: &'static str, R> NextAttribute<R> for StaticAttr<K, V>
@ -187,6 +199,25 @@ where
}
}
impl<R, const V: &'static str> AddAnyAttr<R> for Static<V>
where
R: Renderer,
{
type Output<SomeNewAttr: Attribute<R>> = Static<V>;
fn add_any_attr<NewAttr: Attribute<R>>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<R>,
{
// TODO: there is a strange compiler thing that seems to prevent us returning Self here,
// even though we've already said that Output is always the same as Self
todo!()
}
}
impl<const V: &'static str> ToTemplate for Static<V> {
const TEMPLATE: &'static str = V;

View file

@ -3,10 +3,16 @@ use super::{
};
use crate::{
hydration::Cursor,
no_attrs,
renderer::{CastFrom, Renderer},
};
use std::{borrow::Cow, rc::Rc, sync::Arc};
no_attrs!(&'a str);
no_attrs!(String);
no_attrs!(Arc<str>);
no_attrs!(Cow<'a, str>);
pub struct StrState<'a, R: Renderer> {
pub node: R::Text,
str: &'a str,

View file

@ -1,14 +1,13 @@
use super::{
Mountable, Position, PositionState, Render, RenderHtml, ToTemplate,
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
RenderHtml, ToTemplate,
};
use crate::{
html::attribute::Attribute, hydration::Cursor, renderer::DomRenderer,
};
use crate::{hydration::Cursor, renderer::DomRenderer};
use std::marker::PhantomData;
pub struct ViewTemplate<V, R>
where
V: Render<R> + ToTemplate,
R: DomRenderer,
{
pub struct ViewTemplate<V, R> {
view: V,
rndr: PhantomData<R>,
}
@ -52,6 +51,25 @@ where
}
}
impl<V, R> AddAnyAttr<R> for ViewTemplate<V, R>
where
V: RenderHtml<R> + ToTemplate + 'static,
V::State: Mountable<R>,
R: DomRenderer,
{
type Output<SomeNewAttr: Attribute<R>> = ViewTemplate<V, R>;
fn add_any_attr<NewAttr: Attribute<R>>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<R>,
{
panic!("AddAnyAttr not supported on ViewTemplate");
}
}
impl<V, R> RenderHtml<R> for ViewTemplate<V, R>
where
V: RenderHtml<R> + ToTemplate + 'static,

View file

@ -52,15 +52,7 @@ where
where
Self::Output<NewAttr>: RenderHtml<Rndr>,
{
}
fn add_any_attr_by_ref<NewAttr: Attribute<Rndr>>(
self,
_attr: &NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<Rndr>,
{
().add_any_attr(_attr)
}
}
@ -175,16 +167,6 @@ where
{
(self.0.add_any_attr(attr),)
}
fn add_any_attr_by_ref<NewAttr: Attribute<Rndr>>(
self,
attr: &NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<Rndr>,
{
(self.0.add_any_attr_by_ref(attr),)
}
}
macro_rules! impl_view_for_tuples {
@ -343,7 +325,7 @@ macro_rules! impl_view_for_tuples {
$($ty: AddAnyAttr<Rndr>),*,
Rndr: Renderer,
{
type Output<SomeNewAttr: Attribute<Rndr>> = ($first::Output<SomeNewAttr>, $($ty::Output<SomeNewAttr>,)*);
type Output<SomeNewAttr: Attribute<Rndr>> = ($first::Output<SomeNewAttr::Cloneable>, $($ty::Output<SomeNewAttr::Cloneable>,)*);
fn add_any_attr<NewAttr: Attribute<Rndr>>(
self,
@ -352,22 +334,9 @@ macro_rules! impl_view_for_tuples {
where
Self::Output<NewAttr>: RenderHtml<Rndr>,
{
self.add_any_attr_by_ref(&attr)
}
fn add_any_attr_by_ref<NewAttr: Attribute<Rndr>>(
self,
attr: &NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<Rndr>,
{
#[allow(non_snake_case)]
let shared = attr.into_cloneable();
let ($first, $($ty,)*) = self;
(
$first.add_any_attr_by_ref(&attr),
$($ty.add_any_attr_by_ref(&attr)),*
)
($first.add_any_attr(shared.clone()), $($ty.add_any_attr(shared.clone()),)*)
}
}
};