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