1use super::{
2 add_attr::AddAnyAttr, MarkBranch, Mountable, Position, PositionState,
3 Render, RenderHtml,
4};
5use crate::{
6 html::attribute::{Attribute, NextAttribute},
7 hydration::Cursor,
8 ssr::StreamBuilder,
9};
10use either_of::*;
11use futures::future::join;
12
13impl<A, B> Render for Either<A, B>
14where
15 A: Render,
16 B: Render,
17{
18 type State = Either<A::State, B::State>;
19
20 fn build(self) -> Self::State {
21 match self {
22 Either::Left(left) => Either::Left(left.build()),
23 Either::Right(right) => Either::Right(right.build()),
24 }
25 }
26
27 fn rebuild(self, state: &mut Self::State) {
28 match (self, &mut *state) {
29 (Either::Left(new), Either::Left(old)) => {
30 new.rebuild(old);
31 }
32 (Either::Right(new), Either::Right(old)) => {
33 new.rebuild(old);
34 }
35 (Either::Right(new), Either::Left(old)) => {
36 let mut new_state = new.build();
37 old.insert_before_this(&mut new_state);
38 old.unmount();
39 *state = Either::Right(new_state);
40 }
41 (Either::Left(new), Either::Right(old)) => {
42 let mut new_state = new.build();
43 old.insert_before_this(&mut new_state);
44 old.unmount();
45 *state = Either::Left(new_state);
46 }
47 }
48 }
49}
50
51impl<A, B> Mountable for Either<A, B>
52where
53 A: Mountable,
54 B: Mountable,
55{
56 fn unmount(&mut self) {
57 match self {
58 Either::Left(left) => left.unmount(),
59 Either::Right(right) => right.unmount(),
60 }
61 }
62
63 fn mount(
64 &mut self,
65 parent: &crate::renderer::types::Element,
66 marker: Option<&crate::renderer::types::Node>,
67 ) {
68 match self {
69 Either::Left(left) => left.mount(parent, marker),
70 Either::Right(right) => right.mount(parent, marker),
71 }
72 }
73
74 fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
75 match &self {
76 Either::Left(left) => left.insert_before_this(child),
77 Either::Right(right) => right.insert_before_this(child),
78 }
79 }
80}
81
82impl<A, B> AddAnyAttr for Either<A, B>
83where
84 A: RenderHtml,
85 B: RenderHtml,
86{
87 type Output<SomeNewAttr: Attribute> = Either<
88 <A as AddAnyAttr>::Output<SomeNewAttr>,
89 <B as AddAnyAttr>::Output<SomeNewAttr>,
90 >;
91
92 fn add_any_attr<NewAttr: Attribute>(
93 self,
94 attr: NewAttr,
95 ) -> Self::Output<NewAttr>
96 where
97 Self::Output<NewAttr>: RenderHtml,
98 {
99 match self {
100 Either::Left(i) => Either::Left(i.add_any_attr(attr)),
101 Either::Right(i) => Either::Right(i.add_any_attr(attr)),
102 }
103 }
104}
105
106const fn max_usize(vals: &[usize]) -> usize {
107 let mut max = 0;
108 let len = vals.len();
109 let mut i = 0;
110 while i < len {
111 if vals[i] > max {
112 max = vals[i];
113 }
114 i += 1;
115 }
116 max
117}
118
119#[cfg(not(erase_components))]
120impl<A, B> NextAttribute for Either<A, B>
121where
122 B: NextAttribute,
123 A: NextAttribute,
124{
125 type Output<NewAttr: Attribute> = Either<
126 <A as NextAttribute>::Output<NewAttr>,
127 <B as NextAttribute>::Output<NewAttr>,
128 >;
129
130 fn add_any_attr<NewAttr: Attribute>(
131 self,
132 new_attr: NewAttr,
133 ) -> Self::Output<NewAttr> {
134 match self {
135 Either::Left(left) => Either::Left(left.add_any_attr(new_attr)),
136 Either::Right(right) => Either::Right(right.add_any_attr(new_attr)),
137 }
138 }
139}
140
141#[cfg(erase_components)]
142use crate::html::attribute::any_attribute::{AnyAttribute, IntoAnyAttribute};
143
144#[cfg(erase_components)]
145impl<A, B> NextAttribute for Either<A, B>
146where
147 B: IntoAnyAttribute,
148 A: IntoAnyAttribute,
149{
150 type Output<NewAttr: Attribute> = Vec<AnyAttribute>;
151
152 fn add_any_attr<NewAttr: Attribute>(
153 self,
154 new_attr: NewAttr,
155 ) -> Self::Output<NewAttr> {
156 vec![
157 match self {
158 Either::Left(left) => left.into_any_attr(),
159 Either::Right(right) => right.into_any_attr(),
160 },
161 new_attr.into_any_attr(),
162 ]
163 }
164}
165
166impl<A, B> Attribute for Either<A, B>
167where
168 B: Attribute,
169 A: Attribute,
170{
171 const MIN_LENGTH: usize = max_usize(&[A::MIN_LENGTH, B::MIN_LENGTH]);
172
173 type AsyncOutput = Either<A::AsyncOutput, B::AsyncOutput>;
174 type State = Either<A::State, B::State>;
175 type Cloneable = Either<A::Cloneable, B::Cloneable>;
176 type CloneableOwned = Either<A::CloneableOwned, B::CloneableOwned>;
177
178 fn html_len(&self) -> usize {
179 match self {
180 Either::Left(left) => left.html_len(),
181 Either::Right(right) => right.html_len(),
182 }
183 }
184
185 fn to_html(
186 self,
187 buf: &mut String,
188 class: &mut String,
189 style: &mut String,
190 inner_html: &mut String,
191 ) {
192 match self {
193 Either::Left(left) => left.to_html(buf, class, style, inner_html),
194 Either::Right(right) => {
195 right.to_html(buf, class, style, inner_html)
196 }
197 }
198 }
199
200 fn hydrate<const FROM_SERVER: bool>(
201 self,
202 el: &crate::renderer::types::Element,
203 ) -> Self::State {
204 match self {
205 Either::Left(left) => Either::Left(left.hydrate::<FROM_SERVER>(el)),
206 Either::Right(right) => {
207 Either::Right(right.hydrate::<FROM_SERVER>(el))
208 }
209 }
210 }
211
212 fn build(self, el: &crate::renderer::types::Element) -> Self::State {
213 match self {
214 Either::Left(left) => Either::Left(left.build(el)),
215 Either::Right(right) => Either::Right(right.build(el)),
216 }
217 }
218
219 fn rebuild(self, state: &mut Self::State) {
220 match self {
221 Either::Left(left) => {
222 if let Some(state) = state.as_left_mut() {
223 left.rebuild(state)
224 }
225 }
226 Either::Right(right) => {
227 if let Some(state) = state.as_right_mut() {
228 right.rebuild(state)
229 }
230 }
231 }
232 }
233
234 fn into_cloneable(self) -> Self::Cloneable {
235 match self {
236 Either::Left(left) => Either::Left(left.into_cloneable()),
237 Either::Right(right) => Either::Right(right.into_cloneable()),
238 }
239 }
240
241 fn into_cloneable_owned(self) -> Self::CloneableOwned {
242 match self {
243 Either::Left(left) => Either::Left(left.into_cloneable_owned()),
244 Either::Right(right) => Either::Right(right.into_cloneable_owned()),
245 }
246 }
247
248 fn dry_resolve(&mut self) {
249 match self {
250 Either::Left(left) => left.dry_resolve(),
251 Either::Right(right) => right.dry_resolve(),
252 }
253 }
254
255 async fn resolve(self) -> Self::AsyncOutput {
256 match self {
257 Either::Left(left) => Either::Left(left.resolve().await),
258 Either::Right(right) => Either::Right(right.resolve().await),
259 }
260 }
261}
262
263impl<A, B> RenderHtml for Either<A, B>
264where
265 A: RenderHtml,
266 B: RenderHtml,
267{
268 type AsyncOutput = Either<A::AsyncOutput, B::AsyncOutput>;
269
270 fn dry_resolve(&mut self) {
271 match self {
272 Either::Left(left) => left.dry_resolve(),
273 Either::Right(right) => right.dry_resolve(),
274 }
275 }
276
277 async fn resolve(self) -> Self::AsyncOutput {
278 match self {
279 Either::Left(left) => Either::Left(left.resolve().await),
280 Either::Right(right) => Either::Right(right.resolve().await),
281 }
282 }
283
284 const MIN_LENGTH: usize = max_usize(&[A::MIN_LENGTH, B::MIN_LENGTH]);
285
286 #[inline(always)]
287 fn html_len(&self) -> usize {
288 match self {
289 Either::Left(i) => i.html_len(),
290 Either::Right(i) => i.html_len(),
291 }
292 }
293
294 fn to_html_with_buf(
295 self,
296 buf: &mut String,
297 position: &mut Position,
298 escape: bool,
299 mark_branches: bool,
300 ) {
301 match self {
302 Either::Left(left) => {
303 if mark_branches {
304 buf.open_branch("0");
305 }
306 left.to_html_with_buf(buf, position, escape, mark_branches);
307 if mark_branches {
308 buf.close_branch("0");
309 }
310 }
311 Either::Right(right) => {
312 if mark_branches {
313 buf.open_branch("1");
314 }
315 right.to_html_with_buf(buf, position, escape, mark_branches);
316 if mark_branches {
317 buf.close_branch("1");
318 }
319 }
320 }
321 }
322
323 fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
324 self,
325 buf: &mut StreamBuilder,
326 position: &mut Position,
327 escape: bool,
328 mark_branches: bool,
329 ) where
330 Self: Sized,
331 {
332 match self {
333 Either::Left(left) => {
334 if mark_branches {
335 buf.open_branch("0");
336 }
337 left.to_html_async_with_buf::<OUT_OF_ORDER>(
338 buf,
339 position,
340 escape,
341 mark_branches,
342 );
343 if mark_branches {
344 buf.close_branch("0");
345 }
346 }
347 Either::Right(right) => {
348 if mark_branches {
349 buf.open_branch("1");
350 }
351 right.to_html_async_with_buf::<OUT_OF_ORDER>(
352 buf,
353 position,
354 escape,
355 mark_branches,
356 );
357 if mark_branches {
358 buf.close_branch("1");
359 }
360 }
361 }
362 }
363
364 fn hydrate<const FROM_SERVER: bool>(
365 self,
366 cursor: &Cursor,
367 position: &PositionState,
368 ) -> Self::State {
369 match self {
370 Either::Left(left) => {
371 Either::Left(left.hydrate::<FROM_SERVER>(cursor, position))
372 }
373 Either::Right(right) => {
374 Either::Right(right.hydrate::<FROM_SERVER>(cursor, position))
375 }
376 }
377 }
378}
379
380pub struct EitherKeepAlive<A, B> {
382 pub a: Option<A>,
384 pub b: Option<B>,
386 pub show_b: bool,
388}
389
390pub struct EitherKeepAliveState<A, B> {
392 a: Option<A>,
393 b: Option<B>,
394 showing_b: bool,
395}
396
397impl<A, B> Render for EitherKeepAlive<A, B>
398where
399 A: Render,
400 B: Render,
401{
402 type State = EitherKeepAliveState<A::State, B::State>;
403
404 fn build(self) -> Self::State {
405 let showing_b = self.show_b;
406 let a = self.a.map(Render::build);
407 let b = self.b.map(Render::build);
408 EitherKeepAliveState { a, b, showing_b }
409 }
410
411 fn rebuild(self, state: &mut Self::State) {
412 match (self.a, &mut state.a) {
414 (Some(new), Some(old)) => new.rebuild(old),
415 (Some(new), None) => state.a = Some(new.build()),
416 _ => {}
417 }
418
419 match (self.b, &mut state.b) {
421 (Some(new), Some(old)) => new.rebuild(old),
422 (Some(new), None) => state.b = Some(new.build()),
423 _ => {}
424 }
425
426 match (self.show_b, state.showing_b) {
427 (true, false) => match (&mut state.a, &mut state.b) {
429 (Some(a), Some(b)) => {
430 a.insert_before_this(b);
431 a.unmount();
432 }
433 _ => unreachable!(),
434 },
435 (false, true) => match (&mut state.a, &mut state.b) {
437 (Some(a), Some(b)) => {
438 b.insert_before_this(a);
439 b.unmount();
440 }
441 _ => unreachable!(),
442 },
443 _ => {}
444 }
445 state.showing_b = self.show_b;
446 }
447}
448
449impl<A, B> AddAnyAttr for EitherKeepAlive<A, B>
450where
451 A: RenderHtml,
452 B: RenderHtml,
453{
454 type Output<SomeNewAttr: Attribute> = EitherKeepAlive<
455 <A as AddAnyAttr>::Output<SomeNewAttr::Cloneable>,
456 <B as AddAnyAttr>::Output<SomeNewAttr::Cloneable>,
457 >;
458
459 fn add_any_attr<NewAttr: Attribute>(
460 self,
461 attr: NewAttr,
462 ) -> Self::Output<NewAttr>
463 where
464 Self::Output<NewAttr>: RenderHtml,
465 {
466 let EitherKeepAlive { a, b, show_b } = self;
467 let attr = attr.into_cloneable();
468 EitherKeepAlive {
469 a: a.map(|a| a.add_any_attr(attr.clone())),
470 b: b.map(|b| b.add_any_attr(attr.clone())),
471 show_b,
472 }
473 }
474}
475
476impl<A, B> RenderHtml for EitherKeepAlive<A, B>
477where
478 A: RenderHtml,
479 B: RenderHtml,
480{
481 type AsyncOutput = EitherKeepAlive<A::AsyncOutput, B::AsyncOutput>;
482
483 const MIN_LENGTH: usize = 0;
484
485 fn dry_resolve(&mut self) {
486 if let Some(inner) = &mut self.a {
487 inner.dry_resolve();
488 }
489 if let Some(inner) = &mut self.b {
490 inner.dry_resolve();
491 }
492 }
493
494 async fn resolve(self) -> Self::AsyncOutput {
495 let EitherKeepAlive { a, b, show_b } = self;
496 let (a, b) = join(
497 async move {
498 match a {
499 Some(a) => Some(a.resolve().await),
500 None => None,
501 }
502 },
503 async move {
504 match b {
505 Some(b) => Some(b.resolve().await),
506 None => None,
507 }
508 },
509 )
510 .await;
511 EitherKeepAlive { a, b, show_b }
512 }
513
514 fn to_html_with_buf(
515 self,
516 buf: &mut String,
517 position: &mut Position,
518 escape: bool,
519 mark_branches: bool,
520 ) {
521 if self.show_b {
522 self.b
523 .expect("rendering B to HTML without filling it")
524 .to_html_with_buf(buf, position, escape, mark_branches);
525 } else {
526 self.a
527 .expect("rendering A to HTML without filling it")
528 .to_html_with_buf(buf, position, escape, mark_branches);
529 }
530 }
531
532 fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
533 self,
534 buf: &mut StreamBuilder,
535 position: &mut Position,
536 escape: bool,
537 mark_branches: bool,
538 ) where
539 Self: Sized,
540 {
541 if self.show_b {
542 self.b
543 .expect("rendering B to HTML without filling it")
544 .to_html_async_with_buf::<OUT_OF_ORDER>(
545 buf,
546 position,
547 escape,
548 mark_branches,
549 );
550 } else {
551 self.a
552 .expect("rendering A to HTML without filling it")
553 .to_html_async_with_buf::<OUT_OF_ORDER>(
554 buf,
555 position,
556 escape,
557 mark_branches,
558 );
559 }
560 }
561
562 fn hydrate<const FROM_SERVER: bool>(
563 self,
564 cursor: &Cursor,
565 position: &PositionState,
566 ) -> Self::State {
567 let showing_b = self.show_b;
568 let a = self.a.map(|a| {
569 if showing_b {
570 a.build()
571 } else {
572 a.hydrate::<FROM_SERVER>(cursor, position)
573 }
574 });
575 let b = self.b.map(|b| {
576 if showing_b {
577 b.hydrate::<FROM_SERVER>(cursor, position)
578 } else {
579 b.build()
580 }
581 });
582
583 EitherKeepAliveState { showing_b, a, b }
584 }
585}
586
587impl<A, B> Mountable for EitherKeepAliveState<A, B>
588where
589 A: Mountable,
590 B: Mountable,
591{
592 fn unmount(&mut self) {
593 if self.showing_b {
594 self.b.as_mut().expect("B was not present").unmount();
595 } else {
596 self.a.as_mut().expect("A was not present").unmount();
597 }
598 }
599
600 fn mount(
601 &mut self,
602 parent: &crate::renderer::types::Element,
603 marker: Option<&crate::renderer::types::Node>,
604 ) {
605 if self.showing_b {
606 self.b
607 .as_mut()
608 .expect("B was not present")
609 .mount(parent, marker);
610 } else {
611 self.a
612 .as_mut()
613 .expect("A was not present")
614 .mount(parent, marker);
615 }
616 }
617
618 fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
619 if self.showing_b {
620 self.b
621 .as_ref()
622 .expect("B was not present")
623 .insert_before_this(child)
624 } else {
625 self.a
626 .as_ref()
627 .expect("A was not present")
628 .insert_before_this(child)
629 }
630 }
631}
632
633macro_rules! tuples {
634 ($num:literal => $($ty:ident),*) => {
635 paste::paste! {
636 #[doc = concat!("Retained view state for ", stringify!([<EitherOf $num>]), ".")]
637 pub struct [<EitherOf $num State>]<$($ty,)*>
638 where
639 $($ty: Render,)*
640
641 {
642 pub state: [<EitherOf $num>]<$($ty::State,)*>,
644 }
645
646 impl<$($ty,)*> Mountable for [<EitherOf $num State>]<$($ty,)*>
647 where
648 $($ty: Render,)*
649
650 {
651 fn unmount(&mut self) {
652 match &mut self.state {
653 $([<EitherOf $num>]::$ty(this) => [<EitherOf $num>]::$ty(this.unmount()),)*
654 };
655 }
656
657 fn mount(
658 &mut self,
659 parent: &crate::renderer::types::Element,
660 marker: Option<&crate::renderer::types::Node>,
661 ) {
662 match &mut self.state {
663 $([<EitherOf $num>]::$ty(this) => [<EitherOf $num>]::$ty(this.mount(parent, marker)),)*
664 };
665 }
666
667 fn insert_before_this(&self,
668 child: &mut dyn Mountable,
669 ) -> bool {
670 match &self.state {
671 $([<EitherOf $num>]::$ty(this) =>this.insert_before_this(child),)*
672 }
673 }
674 }
675
676 impl<$($ty,)*> Render for [<EitherOf $num>]<$($ty,)*>
677 where
678 $($ty: Render,)*
679
680 {
681 type State = [<EitherOf $num State>]<$($ty,)*>;
682
683
684 fn build(self) -> Self::State {
685 let state = match self {
686 $([<EitherOf $num>]::$ty(this) => [<EitherOf $num>]::$ty(this.build()),)*
687 };
688 Self::State { state }
689 }
690
691 fn rebuild(self, state: &mut Self::State) {
692 let new_state = match (self, &mut state.state) {
693 $(([<EitherOf $num>]::$ty(new), [<EitherOf $num>]::$ty(old)) => { return new.rebuild(old); },)*
695 $(([<EitherOf $num>]::$ty(new), _) => {
697 let mut new = new.build();
698 state.insert_before_this(&mut new);
699 [<EitherOf $num>]::$ty(new)
700 },)*
701 };
702
703 match &mut state.state {
705 $([<EitherOf $num>]::$ty(this) => this.unmount(),)*
706 };
707
708 state.state = new_state;
710 }
711 }
712
713 impl<$($ty,)*> AddAnyAttr for [<EitherOf $num>]<$($ty,)*>
714 where
715 $($ty: RenderHtml,)*
716
717 {
718 type Output<SomeNewAttr: Attribute> = [<EitherOf $num>]<
719 $(<$ty as AddAnyAttr>::Output<SomeNewAttr>,)*
720 >;
721
722 fn add_any_attr<NewAttr: Attribute>(
723 self,
724 attr: NewAttr,
725 ) -> Self::Output<NewAttr>
726 where
727 Self::Output<NewAttr>: RenderHtml,
728 {
729 match self {
730 $([<EitherOf $num>]::$ty(this) => [<EitherOf $num>]::$ty(this.add_any_attr(attr)),)*
731 }
732 }
733 }
734
735 impl<$($ty,)*> RenderHtml for [<EitherOf $num>]<$($ty,)*>
736 where
737 $($ty: RenderHtml,)*
738
739 {
740 type AsyncOutput = [<EitherOf $num>]<$($ty::AsyncOutput,)*>;
741
742 const MIN_LENGTH: usize = max_usize(&[$($ty ::MIN_LENGTH,)*]);
743
744
745 fn dry_resolve(&mut self) {
746 match self {
747 $([<EitherOf $num>]::$ty(this) => {
748 this.dry_resolve();
749 })*
750 }
751 }
752
753 async fn resolve(self) -> Self::AsyncOutput {
754 match self {
755 $([<EitherOf $num>]::$ty(this) => [<EitherOf $num>]::$ty(this.resolve().await),)*
756 }
757 }
758
759 #[inline(always)]
760 fn html_len(&self) -> usize {
761 match self {
762 $([<EitherOf $num>]::$ty(i) => i.html_len(),)*
763 }
764 }
765
766 fn to_html_with_buf(self, buf: &mut String, position: &mut Position, escape: bool, mark_branches: bool) {
767 match self {
768 $([<EitherOf $num>]::$ty(this) => {
769 if mark_branches {
770 buf.open_branch(stringify!($ty));
771 }
772 this.to_html_with_buf(buf, position, escape, mark_branches);
773 if mark_branches {
774 buf.close_branch(stringify!($ty));
775 }
776 })*
777 }
778 }
779
780 fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
781 self,
782 buf: &mut StreamBuilder, position: &mut Position, escape: bool, mark_branches: bool) where
783 Self: Sized,
784 {
785 match self {
786 $([<EitherOf $num>]::$ty(this) => {
787 if mark_branches {
788 buf.open_branch(stringify!($ty));
789 }
790 this.to_html_async_with_buf::<OUT_OF_ORDER>(buf, position, escape, mark_branches);
791 if mark_branches {
792 buf.close_branch(stringify!($ty));
793 }
794 })*
795 }
796 }
797
798 fn hydrate<const FROM_SERVER: bool>(
799 self,
800 cursor: &Cursor,
801 position: &PositionState,
802 ) -> Self::State {
803 let state = match self {
804 $([<EitherOf $num>]::$ty(this) => {
805 [<EitherOf $num>]::$ty(this.hydrate::<FROM_SERVER>(cursor, position))
806 })*
807 };
808
809 Self::State { state }
810 }
811 }
812 }
813 }
814}
815
816tuples!(3 => A, B, C);
817tuples!(4 => A, B, C, D);
818tuples!(5 => A, B, C, D, E);
819tuples!(6 => A, B, C, D, E, F);
820tuples!(7 => A, B, C, D, E, F, G);
821tuples!(8 => A, B, C, D, E, F, G, H);
822tuples!(9 => A, B, C, D, E, F, G, H, I);
823tuples!(10 => A, B, C, D, E, F, G, H, I, J);
824tuples!(11 => A, B, C, D, E, F, G, H, I, J, K);
825tuples!(12 => A, B, C, D, E, F, G, H, I, J, K, L);
826tuples!(13 => A, B, C, D, E, F, G, H, I, J, K, L, M);
827tuples!(14 => A, B, C, D, E, F, G, H, I, J, K, L, M, N);
828tuples!(15 => A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
829tuples!(16 => A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);