tachys/view/
either.rs

1use super::{
2    add_attr::AddAnyAttr, MarkBranch, Mountable, Position, PositionState,
3    Render, RenderHtml,
4};
5use crate::{
6    html::attribute::{
7        any_attribute::AnyAttribute, Attribute, NamedAttributeKey,
8        NextAttribute,
9    },
10    hydration::Cursor,
11    ssr::StreamBuilder,
12};
13use either_of::*;
14use futures::future::join;
15
16impl<A, B> Render for Either<A, B>
17where
18    A: Render,
19    B: Render,
20{
21    type State = Either<A::State, B::State>;
22
23    fn build(self) -> Self::State {
24        match self {
25            Either::Left(left) => Either::Left(left.build()),
26            Either::Right(right) => Either::Right(right.build()),
27        }
28    }
29
30    fn rebuild(self, state: &mut Self::State) {
31        match (self, &mut *state) {
32            (Either::Left(new), Either::Left(old)) => {
33                new.rebuild(old);
34            }
35            (Either::Right(new), Either::Right(old)) => {
36                new.rebuild(old);
37            }
38            (Either::Right(new), Either::Left(old)) => {
39                let mut new_state = new.build();
40                old.insert_before_this(&mut new_state);
41                old.unmount();
42                *state = Either::Right(new_state);
43            }
44            (Either::Left(new), Either::Right(old)) => {
45                let mut new_state = new.build();
46                old.insert_before_this(&mut new_state);
47                old.unmount();
48                *state = Either::Left(new_state);
49            }
50        }
51    }
52}
53
54impl<A, B> Mountable for Either<A, B>
55where
56    A: Mountable,
57    B: Mountable,
58{
59    fn unmount(&mut self) {
60        match self {
61            Either::Left(left) => left.unmount(),
62            Either::Right(right) => right.unmount(),
63        }
64    }
65
66    fn mount(
67        &mut self,
68        parent: &crate::renderer::types::Element,
69        marker: Option<&crate::renderer::types::Node>,
70    ) {
71        match self {
72            Either::Left(left) => left.mount(parent, marker),
73            Either::Right(right) => right.mount(parent, marker),
74        }
75    }
76
77    fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
78        match &self {
79            Either::Left(left) => left.insert_before_this(child),
80            Either::Right(right) => right.insert_before_this(child),
81        }
82    }
83
84    fn elements(&self) -> Vec<crate::renderer::types::Element> {
85        match &self {
86            Either::Left(left) => left.elements(),
87            Either::Right(right) => right.elements(),
88        }
89    }
90}
91
92impl<A, B> AddAnyAttr for Either<A, B>
93where
94    A: RenderHtml,
95    B: RenderHtml,
96{
97    type Output<SomeNewAttr: Attribute> = Either<
98        <A as AddAnyAttr>::Output<SomeNewAttr>,
99        <B as AddAnyAttr>::Output<SomeNewAttr>,
100    >;
101
102    fn add_any_attr<NewAttr: Attribute>(
103        self,
104        attr: NewAttr,
105    ) -> Self::Output<NewAttr>
106    where
107        Self::Output<NewAttr>: RenderHtml,
108    {
109        match self {
110            Either::Left(i) => Either::Left(i.add_any_attr(attr)),
111            Either::Right(i) => Either::Right(i.add_any_attr(attr)),
112        }
113    }
114}
115
116const fn max_usize(vals: &[usize]) -> usize {
117    let mut max = 0;
118    let len = vals.len();
119    let mut i = 0;
120    while i < len {
121        if vals[i] > max {
122            max = vals[i];
123        }
124        i += 1;
125    }
126    max
127}
128
129#[cfg(not(erase_components))]
130impl<A, B> NextAttribute for Either<A, B>
131where
132    B: NextAttribute,
133    A: NextAttribute,
134{
135    type Output<NewAttr: Attribute> = Either<
136        <A as NextAttribute>::Output<NewAttr>,
137        <B as NextAttribute>::Output<NewAttr>,
138    >;
139
140    fn add_any_attr<NewAttr: Attribute>(
141        self,
142        new_attr: NewAttr,
143    ) -> Self::Output<NewAttr> {
144        match self {
145            Either::Left(left) => Either::Left(left.add_any_attr(new_attr)),
146            Either::Right(right) => Either::Right(right.add_any_attr(new_attr)),
147        }
148    }
149}
150
151#[cfg(erase_components)]
152impl<A, B> NextAttribute for Either<A, B>
153where
154    B: crate::html::attribute::any_attribute::IntoAnyAttribute,
155    A: crate::html::attribute::any_attribute::IntoAnyAttribute,
156{
157    type Output<NewAttr: Attribute> = Vec<AnyAttribute>;
158
159    fn add_any_attr<NewAttr: Attribute>(
160        self,
161        new_attr: NewAttr,
162    ) -> Self::Output<NewAttr> {
163        use crate::html::attribute::any_attribute::IntoAnyAttribute;
164
165        vec![
166            match self {
167                Either::Left(left) => left.into_any_attr(),
168                Either::Right(right) => right.into_any_attr(),
169            },
170            new_attr.into_any_attr(),
171        ]
172    }
173}
174
175impl<A, B> Attribute for Either<A, B>
176where
177    B: Attribute,
178    A: Attribute,
179{
180    const MIN_LENGTH: usize = max_usize(&[A::MIN_LENGTH, B::MIN_LENGTH]);
181
182    type AsyncOutput = Either<A::AsyncOutput, B::AsyncOutput>;
183    type State = Either<A::State, B::State>;
184    type Cloneable = Either<A::Cloneable, B::Cloneable>;
185    type CloneableOwned = Either<A::CloneableOwned, B::CloneableOwned>;
186
187    fn html_len(&self) -> usize {
188        match self {
189            Either::Left(left) => left.html_len(),
190            Either::Right(right) => right.html_len(),
191        }
192    }
193
194    fn to_html(
195        self,
196        buf: &mut String,
197        class: &mut String,
198        style: &mut String,
199        inner_html: &mut String,
200    ) {
201        match self {
202            Either::Left(left) => left.to_html(buf, class, style, inner_html),
203            Either::Right(right) => {
204                right.to_html(buf, class, style, inner_html)
205            }
206        }
207    }
208
209    fn hydrate<const FROM_SERVER: bool>(
210        self,
211        el: &crate::renderer::types::Element,
212    ) -> Self::State {
213        match self {
214            Either::Left(left) => Either::Left(left.hydrate::<FROM_SERVER>(el)),
215            Either::Right(right) => {
216                Either::Right(right.hydrate::<FROM_SERVER>(el))
217            }
218        }
219    }
220
221    fn build(self, el: &crate::renderer::types::Element) -> Self::State {
222        match self {
223            Either::Left(left) => Either::Left(left.build(el)),
224            Either::Right(right) => Either::Right(right.build(el)),
225        }
226    }
227
228    fn rebuild(self, state: &mut Self::State) {
229        match self {
230            Either::Left(left) => {
231                if let Some(state) = state.as_left_mut() {
232                    left.rebuild(state)
233                }
234            }
235            Either::Right(right) => {
236                if let Some(state) = state.as_right_mut() {
237                    right.rebuild(state)
238                }
239            }
240        }
241    }
242
243    fn into_cloneable(self) -> Self::Cloneable {
244        match self {
245            Either::Left(left) => Either::Left(left.into_cloneable()),
246            Either::Right(right) => Either::Right(right.into_cloneable()),
247        }
248    }
249
250    fn into_cloneable_owned(self) -> Self::CloneableOwned {
251        match self {
252            Either::Left(left) => Either::Left(left.into_cloneable_owned()),
253            Either::Right(right) => Either::Right(right.into_cloneable_owned()),
254        }
255    }
256
257    fn dry_resolve(&mut self) {
258        match self {
259            Either::Left(left) => left.dry_resolve(),
260            Either::Right(right) => right.dry_resolve(),
261        }
262    }
263
264    async fn resolve(self) -> Self::AsyncOutput {
265        match self {
266            Either::Left(left) => Either::Left(left.resolve().await),
267            Either::Right(right) => Either::Right(right.resolve().await),
268        }
269    }
270
271    fn keys(&self) -> Vec<NamedAttributeKey> {
272        match self {
273            Either::Left(left) => left.keys(),
274            Either::Right(right) => right.keys(),
275        }
276    }
277}
278
279impl<A, B> RenderHtml for Either<A, B>
280where
281    A: RenderHtml,
282    B: RenderHtml,
283{
284    type AsyncOutput = Either<A::AsyncOutput, B::AsyncOutput>;
285    type Owned = Either<A::Owned, B::Owned>;
286
287    fn dry_resolve(&mut self) {
288        match self {
289            Either::Left(left) => left.dry_resolve(),
290            Either::Right(right) => right.dry_resolve(),
291        }
292    }
293
294    async fn resolve(self) -> Self::AsyncOutput {
295        match self {
296            Either::Left(left) => Either::Left(left.resolve().await),
297            Either::Right(right) => Either::Right(right.resolve().await),
298        }
299    }
300
301    const MIN_LENGTH: usize = max_usize(&[A::MIN_LENGTH, B::MIN_LENGTH]);
302
303    #[inline(always)]
304    fn html_len(&self) -> usize {
305        match self {
306            Either::Left(i) => i.html_len(),
307            Either::Right(i) => i.html_len(),
308        }
309    }
310
311    fn to_html_with_buf(
312        self,
313        buf: &mut String,
314        position: &mut Position,
315        escape: bool,
316        mark_branches: bool,
317        extra_attrs: Vec<AnyAttribute>,
318    ) {
319        match self {
320            Either::Left(left) => {
321                if mark_branches && escape {
322                    buf.open_branch("0");
323                }
324                left.to_html_with_buf(
325                    buf,
326                    position,
327                    escape,
328                    mark_branches,
329                    extra_attrs,
330                );
331                if mark_branches && escape {
332                    buf.close_branch("0");
333                    if *position == Position::NextChildAfterText {
334                        *position = Position::NextChild;
335                    }
336                }
337            }
338            Either::Right(right) => {
339                if mark_branches && escape {
340                    buf.open_branch("1");
341                }
342                right.to_html_with_buf(
343                    buf,
344                    position,
345                    escape,
346                    mark_branches,
347                    extra_attrs,
348                );
349                if mark_branches && escape {
350                    buf.close_branch("1");
351                    if *position == Position::NextChildAfterText {
352                        *position = Position::NextChild;
353                    }
354                }
355            }
356        }
357    }
358
359    fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
360        self,
361        buf: &mut StreamBuilder,
362        position: &mut Position,
363        escape: bool,
364        mark_branches: bool,
365        extra_attrs: Vec<AnyAttribute>,
366    ) where
367        Self: Sized,
368    {
369        match self {
370            Either::Left(left) => {
371                if mark_branches && escape {
372                    buf.open_branch("0");
373                }
374                left.to_html_async_with_buf::<OUT_OF_ORDER>(
375                    buf,
376                    position,
377                    escape,
378                    mark_branches,
379                    extra_attrs,
380                );
381                if mark_branches && escape {
382                    buf.close_branch("0");
383                    if *position == Position::NextChildAfterText {
384                        *position = Position::NextChild;
385                    }
386                }
387            }
388            Either::Right(right) => {
389                if mark_branches && escape {
390                    buf.open_branch("1");
391                }
392                right.to_html_async_with_buf::<OUT_OF_ORDER>(
393                    buf,
394                    position,
395                    escape,
396                    mark_branches,
397                    extra_attrs,
398                );
399                if mark_branches && escape {
400                    buf.close_branch("1");
401                    if *position == Position::NextChildAfterText {
402                        *position = Position::NextChild;
403                    }
404                }
405            }
406        }
407    }
408
409    fn hydrate<const FROM_SERVER: bool>(
410        self,
411        cursor: &Cursor,
412        position: &PositionState,
413    ) -> Self::State {
414        if cfg!(feature = "mark_branches") {
415            cursor.advance_to_placeholder(position);
416        }
417        let state = match self {
418            Either::Left(left) => {
419                Either::Left(left.hydrate::<FROM_SERVER>(cursor, position))
420            }
421            Either::Right(right) => {
422                Either::Right(right.hydrate::<FROM_SERVER>(cursor, position))
423            }
424        };
425        if cfg!(feature = "mark_branches") {
426            cursor.advance_to_placeholder(position);
427        }
428        state
429    }
430
431    async fn hydrate_async(
432        self,
433        cursor: &Cursor,
434        position: &PositionState,
435    ) -> Self::State {
436        if cfg!(feature = "mark_branches") {
437            cursor.advance_to_placeholder(position);
438        }
439        let state = match self {
440            Either::Left(left) => {
441                Either::Left(left.hydrate_async(cursor, position).await)
442            }
443            Either::Right(right) => {
444                Either::Right(right.hydrate_async(cursor, position).await)
445            }
446        };
447        if cfg!(feature = "mark_branches") {
448            cursor.advance_to_placeholder(position);
449        }
450        state
451    }
452
453    fn into_owned(self) -> Self::Owned {
454        match self {
455            Either::Left(left) => Either::Left(left.into_owned()),
456            Either::Right(right) => Either::Right(right.into_owned()),
457        }
458    }
459}
460
461/// Stores each value in the view state, overwriting it only if `Some(_)` is provided.
462pub struct EitherKeepAlive<A, B> {
463    /// The first possibility.
464    pub a: Option<A>,
465    /// The second possibility.
466    pub b: Option<B>,
467    /// If `true`, then `b` will be shown.
468    pub show_b: bool,
469}
470
471/// Retained view state for [`EitherKeepAlive`].
472pub struct EitherKeepAliveState<A, B> {
473    a: Option<A>,
474    b: Option<B>,
475    showing_b: bool,
476}
477
478impl<A, B> Render for EitherKeepAlive<A, B>
479where
480    A: Render,
481    B: Render,
482{
483    type State = EitherKeepAliveState<A::State, B::State>;
484
485    fn build(self) -> Self::State {
486        let showing_b = self.show_b;
487        let a = self.a.map(Render::build);
488        let b = self.b.map(Render::build);
489        EitherKeepAliveState { a, b, showing_b }
490    }
491
492    fn rebuild(self, state: &mut Self::State) {
493        // set or update A -- `None` just means "no change"
494        match (self.a, &mut state.a) {
495            (Some(new), Some(old)) => new.rebuild(old),
496            (Some(new), None) => state.a = Some(new.build()),
497            _ => {}
498        }
499
500        // set or update B
501        match (self.b, &mut state.b) {
502            (Some(new), Some(old)) => new.rebuild(old),
503            (Some(new), None) => state.b = Some(new.build()),
504            _ => {}
505        }
506
507        match (self.show_b, state.showing_b) {
508            // transition from A to B
509            (true, false) => match (&mut state.a, &mut state.b) {
510                (Some(a), Some(b)) => {
511                    a.insert_before_this(b);
512                    a.unmount();
513                }
514                _ => unreachable!(),
515            },
516            // transition from B to A
517            (false, true) => match (&mut state.a, &mut state.b) {
518                (Some(a), Some(b)) => {
519                    b.insert_before_this(a);
520                    b.unmount();
521                }
522                _ => unreachable!(),
523            },
524            _ => {}
525        }
526        state.showing_b = self.show_b;
527    }
528}
529
530impl<A, B> AddAnyAttr for EitherKeepAlive<A, B>
531where
532    A: RenderHtml,
533    B: RenderHtml,
534{
535    type Output<SomeNewAttr: Attribute> = EitherKeepAlive<
536        <A as AddAnyAttr>::Output<SomeNewAttr::Cloneable>,
537        <B as AddAnyAttr>::Output<SomeNewAttr::Cloneable>,
538    >;
539
540    fn add_any_attr<NewAttr: Attribute>(
541        self,
542        attr: NewAttr,
543    ) -> Self::Output<NewAttr>
544    where
545        Self::Output<NewAttr>: RenderHtml,
546    {
547        let EitherKeepAlive { a, b, show_b } = self;
548        let attr = attr.into_cloneable();
549        EitherKeepAlive {
550            a: a.map(|a| a.add_any_attr(attr.clone())),
551            b: b.map(|b| b.add_any_attr(attr.clone())),
552            show_b,
553        }
554    }
555}
556
557impl<A, B> RenderHtml for EitherKeepAlive<A, B>
558where
559    A: RenderHtml,
560    B: RenderHtml,
561{
562    type AsyncOutput = EitherKeepAlive<A::AsyncOutput, B::AsyncOutput>;
563    type Owned = EitherKeepAlive<A::Owned, B::Owned>;
564
565    const MIN_LENGTH: usize = 0;
566
567    fn dry_resolve(&mut self) {
568        if let Some(inner) = &mut self.a {
569            inner.dry_resolve();
570        }
571        if let Some(inner) = &mut self.b {
572            inner.dry_resolve();
573        }
574    }
575
576    async fn resolve(self) -> Self::AsyncOutput {
577        let EitherKeepAlive { a, b, show_b } = self;
578        let (a, b) = join(
579            async move {
580                match a {
581                    Some(a) => Some(a.resolve().await),
582                    None => None,
583                }
584            },
585            async move {
586                match b {
587                    Some(b) => Some(b.resolve().await),
588                    None => None,
589                }
590            },
591        )
592        .await;
593        EitherKeepAlive { a, b, show_b }
594    }
595
596    fn to_html_with_buf(
597        self,
598        buf: &mut String,
599        position: &mut Position,
600        escape: bool,
601        mark_branches: bool,
602        extra_attrs: Vec<AnyAttribute>,
603    ) {
604        if self.show_b {
605            self.b
606                .expect("rendering B to HTML without filling it")
607                .to_html_with_buf(
608                    buf,
609                    position,
610                    escape,
611                    mark_branches,
612                    extra_attrs,
613                );
614        } else {
615            self.a
616                .expect("rendering A to HTML without filling it")
617                .to_html_with_buf(
618                    buf,
619                    position,
620                    escape,
621                    mark_branches,
622                    extra_attrs,
623                );
624        }
625    }
626
627    fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
628        self,
629        buf: &mut StreamBuilder,
630        position: &mut Position,
631        escape: bool,
632        mark_branches: bool,
633        extra_attrs: Vec<AnyAttribute>,
634    ) where
635        Self: Sized,
636    {
637        if self.show_b {
638            self.b
639                .expect("rendering B to HTML without filling it")
640                .to_html_async_with_buf::<OUT_OF_ORDER>(
641                    buf,
642                    position,
643                    escape,
644                    mark_branches,
645                    extra_attrs,
646                );
647        } else {
648            self.a
649                .expect("rendering A to HTML without filling it")
650                .to_html_async_with_buf::<OUT_OF_ORDER>(
651                    buf,
652                    position,
653                    escape,
654                    mark_branches,
655                    extra_attrs,
656                );
657        }
658    }
659
660    fn hydrate<const FROM_SERVER: bool>(
661        self,
662        cursor: &Cursor,
663        position: &PositionState,
664    ) -> Self::State {
665        let showing_b = self.show_b;
666        let a = self.a.map(|a| {
667            if showing_b {
668                a.build()
669            } else {
670                a.hydrate::<FROM_SERVER>(cursor, position)
671            }
672        });
673        let b = self.b.map(|b| {
674            if showing_b {
675                b.hydrate::<FROM_SERVER>(cursor, position)
676            } else {
677                b.build()
678            }
679        });
680
681        EitherKeepAliveState { showing_b, a, b }
682    }
683
684    async fn hydrate_async(
685        self,
686        cursor: &Cursor,
687        position: &PositionState,
688    ) -> Self::State {
689        let showing_b = self.show_b;
690        let a = if let Some(a) = self.a {
691            Some(if showing_b {
692                a.build()
693            } else {
694                a.hydrate_async(cursor, position).await
695            })
696        } else {
697            None
698        };
699        let b = if let Some(b) = self.b {
700            Some(if showing_b {
701                b.hydrate_async(cursor, position).await
702            } else {
703                b.build()
704            })
705        } else {
706            None
707        };
708
709        EitherKeepAliveState { showing_b, a, b }
710    }
711
712    fn into_owned(self) -> Self::Owned {
713        EitherKeepAlive {
714            a: self.a.map(|a| a.into_owned()),
715            b: self.b.map(|b| b.into_owned()),
716            show_b: self.show_b,
717        }
718    }
719}
720
721impl<A, B> Mountable for EitherKeepAliveState<A, B>
722where
723    A: Mountable,
724    B: Mountable,
725{
726    fn unmount(&mut self) {
727        if self.showing_b {
728            self.b.as_mut().expect("B was not present").unmount();
729        } else {
730            self.a.as_mut().expect("A was not present").unmount();
731        }
732    }
733
734    fn mount(
735        &mut self,
736        parent: &crate::renderer::types::Element,
737        marker: Option<&crate::renderer::types::Node>,
738    ) {
739        if self.showing_b {
740            self.b
741                .as_mut()
742                .expect("B was not present")
743                .mount(parent, marker);
744        } else {
745            self.a
746                .as_mut()
747                .expect("A was not present")
748                .mount(parent, marker);
749        }
750    }
751
752    fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
753        if self.showing_b {
754            self.b
755                .as_ref()
756                .expect("B was not present")
757                .insert_before_this(child)
758        } else {
759            self.a
760                .as_ref()
761                .expect("A was not present")
762                .insert_before_this(child)
763        }
764    }
765
766    fn elements(&self) -> Vec<crate::renderer::types::Element> {
767        if self.showing_b {
768            self.b
769                .as_ref()
770                .map(|inner| inner.elements())
771                .unwrap_or_default()
772        } else {
773            self.a
774                .as_ref()
775                .map(|inner| inner.elements())
776                .unwrap_or_default()
777        }
778    }
779}
780
781macro_rules! tuples {
782    ($num:literal => $($ty:ident),*) => {
783        paste::paste! {
784            #[doc = concat!("Retained view state for ", stringify!([<EitherOf $num>]), ".")]
785            pub struct [<EitherOf $num State>]<$($ty,)*>
786            where
787                $($ty: Render,)*
788
789            {
790                /// Which child view state is being displayed.
791                pub state: [<EitherOf $num>]<$($ty::State,)*>,
792            }
793
794            impl<$($ty,)*> Mountable for [<EitherOf $num State>]<$($ty,)*>
795            where
796                $($ty: Render,)*
797
798            {
799                fn unmount(&mut self) {
800                    match &mut self.state {
801                        $([<EitherOf $num>]::$ty(this) => [<EitherOf $num>]::$ty(this.unmount()),)*
802                    };
803                }
804
805                fn mount(
806                    &mut self,
807                    parent: &crate::renderer::types::Element,
808                    marker: Option<&crate::renderer::types::Node>,
809                ) {
810                    match &mut self.state {
811                        $([<EitherOf $num>]::$ty(this) => [<EitherOf $num>]::$ty(this.mount(parent, marker)),)*
812                    };
813                }
814
815                fn insert_before_this(&self,
816                    child: &mut dyn Mountable,
817                ) -> bool {
818                    match &self.state {
819                        $([<EitherOf $num>]::$ty(this) =>this.insert_before_this(child),)*
820                    }
821                }
822
823                fn elements(&self) -> Vec<crate::renderer::types::Element> {
824                    match &self.state {
825                        $([<EitherOf $num>]::$ty(this) => this.elements(),)*
826                    }
827                }
828            }
829
830            impl<$($ty,)*> Render for [<EitherOf $num>]<$($ty,)*>
831            where
832                $($ty: Render,)*
833
834            {
835                type State = [<EitherOf $num State>]<$($ty,)*>;
836
837
838                fn build(self) -> Self::State {
839                    let state = match self {
840                        $([<EitherOf $num>]::$ty(this) => [<EitherOf $num>]::$ty(this.build()),)*
841                    };
842                    Self::State { state }
843                }
844
845                fn rebuild(self, state: &mut Self::State) {
846                    let new_state = match (self, &mut state.state) {
847                        // rebuild same state and return early
848                        $(([<EitherOf $num>]::$ty(new), [<EitherOf $num>]::$ty(old)) => { return new.rebuild(old); },)*
849                        // or mount new state
850                        $(([<EitherOf $num>]::$ty(new), _) => {
851                            let mut new = new.build();
852                            state.insert_before_this(&mut new);
853                            [<EitherOf $num>]::$ty(new)
854                        },)*
855                    };
856
857                    // and then unmount old state
858                    match &mut state.state {
859                        $([<EitherOf $num>]::$ty(this) => this.unmount(),)*
860                    };
861
862                    // and store the new state
863                    state.state = new_state;
864                }
865            }
866
867            impl<$($ty,)*> AddAnyAttr for [<EitherOf $num>]<$($ty,)*>
868            where
869                $($ty: RenderHtml,)*
870
871            {
872                type Output<SomeNewAttr: Attribute> = [<EitherOf $num>]<
873                    $(<$ty as AddAnyAttr>::Output<SomeNewAttr>,)*
874                >;
875
876                fn add_any_attr<NewAttr: Attribute>(
877                    self,
878                    attr: NewAttr,
879                ) -> Self::Output<NewAttr>
880                where
881                    Self::Output<NewAttr>: RenderHtml,
882                {
883                    match self {
884                        $([<EitherOf $num>]::$ty(this) => [<EitherOf $num>]::$ty(this.add_any_attr(attr)),)*
885                    }
886                }
887            }
888
889            impl<$($ty,)*> RenderHtml for [<EitherOf $num>]<$($ty,)*>
890            where
891                $($ty: RenderHtml,)*
892
893            {
894                type AsyncOutput = [<EitherOf $num>]<$($ty::AsyncOutput,)*>;
895                type Owned = [<EitherOf $num>]<$($ty::Owned,)*>;
896
897                const MIN_LENGTH: usize = max_usize(&[$($ty ::MIN_LENGTH,)*]);
898
899
900                fn dry_resolve(&mut self) {
901                    match self {
902                        $([<EitherOf $num>]::$ty(this) => {
903                            this.dry_resolve();
904                        })*
905                    }
906                }
907
908                async fn resolve(self) -> Self::AsyncOutput {
909                    match self {
910                        $([<EitherOf $num>]::$ty(this) => [<EitherOf $num>]::$ty(this.resolve().await),)*
911                    }
912                }
913
914                #[inline(always)]
915                fn html_len(&self) -> usize {
916                    match self {
917                        $([<EitherOf $num>]::$ty(i) => i.html_len(),)*
918                    }
919                }
920
921                fn to_html_with_buf(
922                    self,
923                    buf: &mut String,
924                    position: &mut Position,
925                    escape: bool,
926                    mark_branches: bool,
927                    extra_attrs: Vec<AnyAttribute>
928                ) {
929                    match self {
930                        $([<EitherOf $num>]::$ty(this) => {
931                            if mark_branches && escape {
932                                buf.open_branch(stringify!($ty));
933                            }
934                            this.to_html_with_buf(buf, position, escape, mark_branches, extra_attrs);
935                            if mark_branches && escape {
936                                buf.close_branch(stringify!($ty));
937                                if *position == Position::NextChildAfterText {
938                                    *position = Position::NextChild;
939                                }
940                            }
941                        })*
942                    }
943                }
944
945                fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
946                    self,
947                    buf: &mut StreamBuilder,
948                    position: &mut Position,
949                    escape: bool,
950                    mark_branches: bool,
951                    extra_attrs: Vec<AnyAttribute>
952                ) where
953                    Self: Sized,
954                {
955                    match self {
956                        $([<EitherOf $num>]::$ty(this) => {
957                            if mark_branches && escape {
958                                buf.open_branch(stringify!($ty));
959                            }
960                            this.to_html_async_with_buf::<OUT_OF_ORDER>(buf, position, escape, mark_branches, extra_attrs);
961                            if mark_branches && escape {
962                                buf.close_branch(stringify!($ty));
963                                if *position == Position::NextChildAfterText {
964                                    *position = Position::NextChild;
965                                }
966                            }
967                        })*
968                    }
969                }
970
971                fn hydrate<const FROM_SERVER: bool>(
972                    self,
973                    cursor: &Cursor,
974                    position: &PositionState,
975                ) -> Self::State {
976                    if cfg!(feature = "mark_branches") {
977                        cursor.advance_to_placeholder(position);
978                    }
979                    let state = match self {
980                        $([<EitherOf $num>]::$ty(this) => {
981                            [<EitherOf $num>]::$ty(this.hydrate::<FROM_SERVER>(cursor, position))
982                        })*
983                    };
984                    if cfg!(feature = "mark_branches") {
985                        cursor.advance_to_placeholder(position);
986                    }
987
988                    Self::State { state }
989                }
990
991                async fn hydrate_async(
992                    self,
993                    cursor: &Cursor,
994                    position: &PositionState,
995                ) -> Self::State {
996                    if cfg!(feature = "mark_branches") {
997                        cursor.advance_to_placeholder(position);
998                    }
999                    let state = match self {
1000                        $([<EitherOf $num>]::$ty(this) => {
1001                            [<EitherOf $num>]::$ty(this.hydrate_async(cursor, position).await)
1002                        })*
1003                    };
1004                    if cfg!(feature = "mark_branches") {
1005                        cursor.advance_to_placeholder(position);
1006                    }
1007
1008                    Self::State { state }
1009                }
1010
1011                fn into_owned(self) -> Self::Owned {
1012                    match self {
1013                        $([<EitherOf $num>]::$ty(this) => {
1014                            [<EitherOf $num>]::$ty(this.into_owned())
1015                        })*
1016                    }
1017                }
1018            }
1019        }
1020    }
1021}
1022
1023tuples!(3 => A, B, C);
1024tuples!(4 => A, B, C, D);
1025tuples!(5 => A, B, C, D, E);
1026tuples!(6 => A, B, C, D, E, F);
1027tuples!(7 => A, B, C, D, E, F, G);
1028tuples!(8 => A, B, C, D, E, F, G, H);
1029tuples!(9 => A, B, C, D, E, F, G, H, I);
1030tuples!(10 => A, B, C, D, E, F, G, H, I, J);
1031tuples!(11 => A, B, C, D, E, F, G, H, I, J, K);
1032tuples!(12 => A, B, C, D, E, F, G, H, I, J, K, L);
1033tuples!(13 => A, B, C, D, E, F, G, H, I, J, K, L, M);
1034tuples!(14 => A, B, C, D, E, F, G, H, I, J, K, L, M, N);
1035tuples!(15 => A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
1036tuples!(16 => A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);