use super::{
Mountable, Position, PositionState, Render, RenderHtml, ToTemplate,
};
use crate::{
html::attribute::{any_attribute::AnyAttribute, Attribute},
hydration::Cursor,
renderer::Rndr,
view::{add_attr::AddAnyAttr, StreamBuilder},
};
use const_str_slice_concat::{
const_concat, const_concat_with_separator, str_from_buffer,
};
impl Render for () {
type State = crate::renderer::types::Placeholder;
fn build(self) -> Self::State {
Rndr::create_placeholder()
}
fn rebuild(self, _state: &mut Self::State) {}
}
impl RenderHtml for () {
type AsyncOutput = ();
type Owned = ();
const MIN_LENGTH: usize = 3;
const EXISTS: bool = false;
fn to_html_with_buf(
self,
buf: &mut String,
position: &mut Position,
escape: bool,
_mark_branches: bool,
_extra_attrs: Vec<AnyAttribute>,
) {
if escape {
buf.push_str("<!>");
*position = Position::NextChild;
}
}
fn hydrate<const FROM_SERVER: bool>(
self,
cursor: &Cursor,
position: &PositionState,
) -> Self::State {
let marker = cursor.next_placeholder(position);
position.set(Position::NextChild);
marker
}
async fn resolve(self) -> Self::AsyncOutput {}
fn dry_resolve(&mut self) {}
fn into_owned(self) -> Self::Owned {}
}
impl AddAnyAttr for () {
type Output<SomeNewAttr: Attribute> = ();
fn add_any_attr<NewAttr: Attribute>(
self,
_attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml,
{
}
}
impl Mountable for () {
fn unmount(&mut self) {}
fn mount(
&mut self,
_parent: &crate::renderer::types::Element,
_marker: Option<&crate::renderer::types::Node>,
) {
}
fn insert_before_this(&self, _child: &mut dyn Mountable) -> bool {
false
}
fn elements(&self) -> Vec<crate::renderer::types::Element> {
vec![]
}
}
impl ToTemplate for () {
const TEMPLATE: &'static str = "<!>";
fn to_template(
buf: &mut String,
_class: &mut String,
_style: &mut String,
_inner_html: &mut String,
_position: &mut Position,
) {
buf.push_str("<!>");
}
fn to_template_attribute(
_buf: &mut String,
_class: &mut String,
_style: &mut String,
_inner_html: &mut String,
_position: &mut Position,
) {
}
}
impl<A: Render> Render for (A,) {
type State = A::State;
fn build(self) -> Self::State {
self.0.build()
}
fn rebuild(self, state: &mut Self::State) {
self.0.rebuild(state)
}
}
impl<A> RenderHtml for (A,)
where
A: RenderHtml,
{
type AsyncOutput = (A::AsyncOutput,);
type Owned = (A::Owned,);
const MIN_LENGTH: usize = A::MIN_LENGTH;
const EXISTS: bool = A::EXISTS;
fn html_len(&self) -> usize {
self.0.html_len()
}
fn to_html_with_buf(
self,
buf: &mut String,
position: &mut Position,
escape: bool,
mark_branches: bool,
extra_attrs: Vec<AnyAttribute>,
) {
self.0.to_html_with_buf(
buf,
position,
escape,
mark_branches,
extra_attrs,
);
}
fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
self,
buf: &mut StreamBuilder,
position: &mut Position,
escape: bool,
mark_branches: bool,
extra_attrs: Vec<AnyAttribute>,
) where
Self: Sized,
{
self.0.to_html_async_with_buf::<OUT_OF_ORDER>(
buf,
position,
escape,
mark_branches,
extra_attrs,
);
}
fn hydrate<const FROM_SERVER: bool>(
self,
cursor: &Cursor,
position: &PositionState,
) -> Self::State {
self.0.hydrate::<FROM_SERVER>(cursor, position)
}
async fn hydrate_async(
self,
cursor: &Cursor,
position: &PositionState,
) -> Self::State {
self.0.hydrate_async(cursor, position).await
}
async fn resolve(self) -> Self::AsyncOutput {
(self.0.resolve().await,)
}
fn dry_resolve(&mut self) {
self.0.dry_resolve();
}
fn into_owned(self) -> Self::Owned {
(self.0.into_owned(),)
}
}
impl<A: ToTemplate> ToTemplate for (A,) {
const TEMPLATE: &'static str = A::TEMPLATE;
const CLASS: &'static str = A::CLASS;
const STYLE: &'static str = A::STYLE;
fn to_template(
buf: &mut String,
class: &mut String,
style: &mut String,
inner_html: &mut String,
position: &mut Position,
) {
A::to_template(buf, class, style, inner_html, position)
}
}
impl<A> AddAnyAttr for (A,)
where
A: AddAnyAttr,
{
type Output<SomeNewAttr: Attribute> = (A::Output<SomeNewAttr>,);
fn add_any_attr<NewAttr: Attribute>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml,
{
(self.0.add_any_attr(attr),)
}
}
macro_rules! impl_view_for_tuples {
($first:ident, $($ty:ident),* $(,)?) => {
impl<$first, $($ty),*> Render for ($first, $($ty,)*)
where
$first: Render,
$($ty: Render),*,
{
type State = ($first::State, $($ty::State,)*);
fn build(self) -> Self::State {
#[allow(non_snake_case)]
let ($first, $($ty,)*) = self;
(
$first.build(),
$($ty.build()),*
)
}
fn rebuild(self, state: &mut Self::State) {
paste::paste! {
let ([<$first:lower>], $([<$ty:lower>],)*) = self;
let ([<view_ $first:lower>], $([<view_ $ty:lower>],)*) = state;
[<$first:lower>].rebuild([<view_ $first:lower>]);
$([<$ty:lower>].rebuild([<view_ $ty:lower>]));*
}
}
}
impl<$first, $($ty),*> RenderHtml for ($first, $($ty,)*)
where
$first: RenderHtml,
$($ty: RenderHtml),*,
{
type AsyncOutput = ($first::AsyncOutput, $($ty::AsyncOutput,)*);
type Owned = ($first::Owned, $($ty::Owned,)*);
const EXISTS: bool = $first::EXISTS || $($ty::EXISTS || )* false;
const MIN_LENGTH: usize = $first::MIN_LENGTH $(+ $ty::MIN_LENGTH)*;
#[inline(always)]
fn html_len(&self) -> usize {
#[allow(non_snake_case)]
let ($first, $($ty,)* ) = self;
$($ty.html_len() +)* $first.html_len()
}
fn to_html_with_buf(
self,
buf: &mut String,
position: &mut Position,
escape: bool,
mark_branches: bool,
extra_attrs: Vec<AnyAttribute>
) {
#[allow(non_snake_case)]
let ($first, $($ty,)* ) = self;
$first.to_html_with_buf(buf, position, escape, mark_branches, extra_attrs.clone());
$($ty.to_html_with_buf(buf, position, escape, mark_branches, extra_attrs.clone()));*
}
fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
self,
buf: &mut StreamBuilder,
position: &mut Position,
escape: bool,
mark_branches: bool,
extra_attrs: Vec<AnyAttribute>
) where
Self: Sized,
{
#[allow(non_snake_case)]
let ($first, $($ty,)* ) = self;
$first.to_html_async_with_buf::<OUT_OF_ORDER>(buf, position, escape, mark_branches, extra_attrs.clone());
$($ty.to_html_async_with_buf::<OUT_OF_ORDER>(buf, position, escape, mark_branches, extra_attrs.clone()));*
}
fn hydrate<const FROM_SERVER: bool>(self, cursor: &Cursor, position: &PositionState) -> Self::State {
#[allow(non_snake_case)]
let ($first, $($ty,)* ) = self;
(
$first.hydrate::<FROM_SERVER>(cursor, position),
$($ty.hydrate::<FROM_SERVER>(cursor, position)),*
)
}
async fn hydrate_async(self, cursor: &Cursor, position: &PositionState) -> Self::State {
#[allow(non_snake_case)]
let ($first, $($ty,)* ) = self;
(
$first.hydrate_async(cursor, position).await,
$($ty.hydrate_async(cursor, position).await),*
)
}
async fn resolve(self) -> Self::AsyncOutput {
#[allow(non_snake_case)]
let ($first, $($ty,)*) = self;
futures::join!(
$first.resolve(),
$($ty.resolve()),*
)
}
fn dry_resolve(&mut self) {
#[allow(non_snake_case)]
let ($first, $($ty,)*) = self;
$first.dry_resolve();
$($ty.dry_resolve());*
}
fn into_owned(self) -> Self::Owned {
#[allow(non_snake_case)]
let ($first, $($ty,)*) = self;
(
$first.into_owned(),
$($ty.into_owned()),*
)
}
}
impl<$first, $($ty),*> ToTemplate for ($first, $($ty,)*)
where
$first: ToTemplate,
$($ty: ToTemplate),*
{
const TEMPLATE: &'static str = str_from_buffer(&const_concat(&[
$first::TEMPLATE, $($ty::TEMPLATE),*
]));
const CLASS: &'static str = str_from_buffer(&const_concat_with_separator(&[
$first::CLASS, $($ty::CLASS),*
], " "));
const STYLE: &'static str = str_from_buffer(&const_concat_with_separator(&[
$first::STYLE, $($ty::STYLE),*
], ";"));
fn to_template(buf: &mut String, class: &mut String, style: &mut String, inner_html: &mut String, position: &mut Position) {
$first ::to_template(buf, class, style, inner_html, position);
$($ty::to_template(buf, class, style, inner_html, position));*;
}
}
impl<$first, $($ty),*> Mountable for ($first, $($ty,)*) where
$first: Mountable,
$($ty: Mountable),*,
{
fn unmount(&mut self) {
#[allow(non_snake_case)] let ($first, $($ty,)*) = self;
$first.unmount();
$($ty.unmount());*
}
fn mount(
&mut self,
parent: &crate::renderer::types::Element,
marker: Option<&crate::renderer::types::Node>,
) {
#[allow(non_snake_case)] let ($first, $($ty,)*) = self;
$first.mount(parent, marker);
$($ty.mount(parent, marker));*
}
fn insert_before_this(&self,
child: &mut dyn Mountable,
) -> bool {
#[allow(non_snake_case)] let ($first, $($ty,)*) = self;
$first.insert_before_this(child)
$(|| $ty.insert_before_this(child))*
}
fn elements(&self) -> Vec<crate::renderer::types::Element> {
#[allow(non_snake_case)] let ($first, $($ty,)*) = self;
$first.elements().into_iter()
$(.chain($ty.elements()))*
.collect()
}
}
impl<$first, $($ty,)*> AddAnyAttr for ($first, $($ty,)*)
where
$first: AddAnyAttr,
$($ty: AddAnyAttr),*,
{
type Output<SomeNewAttr: Attribute> = ($first::Output<SomeNewAttr::Cloneable>, $($ty::Output<SomeNewAttr::Cloneable>,)*);
fn add_any_attr<NewAttr: Attribute>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml,
{
let shared = attr.into_cloneable();
#[allow(non_snake_case)] let ($first, $($ty,)*) = self;
($first.add_any_attr(shared.clone()), $($ty.add_any_attr(shared.clone()),)*)
}
}
};
}
impl_view_for_tuples!(A, B);
impl_view_for_tuples!(A, B, C);
impl_view_for_tuples!(A, B, C, D);
impl_view_for_tuples!(A, B, C, D, E);
impl_view_for_tuples!(A, B, C, D, E, F);
impl_view_for_tuples!(A, B, C, D, E, F, G);
impl_view_for_tuples!(A, B, C, D, E, F, G, H);
impl_view_for_tuples!(A, B, C, D, E, F, G, H, I);
impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J);
impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K);
impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K, L);
impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M);
impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
impl_view_for_tuples!(
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T
);
impl_view_for_tuples!(
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U
);
impl_view_for_tuples!(
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V
);
impl_view_for_tuples!(
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W
);
impl_view_for_tuples!(
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X
);
impl_view_for_tuples!(
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y
);
impl_view_for_tuples!(
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y,
Z
);