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