Skip to main content

tachys/view/
tuples.rs

1use super::{
2    Mountable, Position, PositionState, Render, RenderHtml, ToTemplate,
3};
4use crate::{
5    html::attribute::{any_attribute::AnyAttribute, Attribute},
6    hydration::Cursor,
7    renderer::Rndr,
8    view::{add_attr::AddAnyAttr, StreamBuilder},
9};
10use const_str_slice_concat::{
11    const_concat, const_concat_with_separator, str_from_buffer,
12};
13
14impl Render for () {
15    type State = crate::renderer::types::Placeholder;
16
17    fn build(self) -> Self::State {
18        Rndr::create_placeholder()
19    }
20
21    fn rebuild(self, _state: &mut Self::State) {}
22}
23
24impl RenderHtml for () {
25    type AsyncOutput = ();
26    type Owned = ();
27
28    const MIN_LENGTH: usize = 3;
29    const EXISTS: bool = false;
30
31    fn to_html_with_buf(
32        self,
33        buf: &mut String,
34        position: &mut Position,
35        escape: bool,
36        _mark_branches: bool,
37        _extra_attrs: Vec<AnyAttribute>,
38    ) {
39        if escape {
40            buf.push_str("<!>");
41            *position = Position::NextChild;
42        }
43    }
44
45    fn hydrate<const FROM_SERVER: bool>(
46        self,
47        cursor: &Cursor,
48        position: &PositionState,
49    ) -> Self::State {
50        let marker = cursor.next_placeholder(position);
51        position.set(Position::NextChild);
52        marker
53    }
54
55    async fn resolve(self) -> Self::AsyncOutput {}
56
57    fn dry_resolve(&mut self) {}
58
59    fn into_owned(self) -> Self::Owned {}
60}
61
62impl AddAnyAttr for () {
63    type Output<SomeNewAttr: Attribute> = ();
64
65    fn add_any_attr<NewAttr: Attribute>(
66        self,
67        _attr: NewAttr,
68    ) -> Self::Output<NewAttr>
69    where
70        Self::Output<NewAttr>: RenderHtml,
71    {
72    }
73}
74
75impl Mountable for () {
76    fn unmount(&mut self) {}
77
78    fn mount(
79        &mut self,
80        _parent: &crate::renderer::types::Element,
81        _marker: Option<&crate::renderer::types::Node>,
82    ) {
83    }
84
85    fn insert_before_this(&self, _child: &mut dyn Mountable) -> bool {
86        false
87    }
88
89    fn elements(&self) -> Vec<crate::renderer::types::Element> {
90        vec![]
91    }
92}
93
94impl ToTemplate for () {
95    const TEMPLATE: &'static str = "<!>";
96
97    fn to_template(
98        buf: &mut String,
99        _class: &mut String,
100        _style: &mut String,
101        _inner_html: &mut String,
102        _position: &mut Position,
103    ) {
104        buf.push_str("<!>");
105    }
106
107    fn to_template_attribute(
108        _buf: &mut String,
109        _class: &mut String,
110        _style: &mut String,
111        _inner_html: &mut String,
112        _position: &mut Position,
113    ) {
114    }
115}
116
117impl<A: Render> Render for (A,) {
118    type State = A::State;
119
120    fn build(self) -> Self::State {
121        self.0.build()
122    }
123
124    fn rebuild(self, state: &mut Self::State) {
125        self.0.rebuild(state)
126    }
127}
128
129impl<A> RenderHtml for (A,)
130where
131    A: RenderHtml,
132{
133    type AsyncOutput = (A::AsyncOutput,);
134    type Owned = (A::Owned,);
135
136    const MIN_LENGTH: usize = A::MIN_LENGTH;
137    const EXISTS: bool = A::EXISTS;
138
139    fn html_len(&self) -> usize {
140        self.0.html_len()
141    }
142
143    fn to_html_with_buf(
144        self,
145        buf: &mut String,
146        position: &mut Position,
147        escape: bool,
148        mark_branches: bool,
149        extra_attrs: Vec<AnyAttribute>,
150    ) {
151        self.0.to_html_with_buf(
152            buf,
153            position,
154            escape,
155            mark_branches,
156            extra_attrs,
157        );
158    }
159
160    fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
161        self,
162        buf: &mut StreamBuilder,
163        position: &mut Position,
164        escape: bool,
165        mark_branches: bool,
166        extra_attrs: Vec<AnyAttribute>,
167    ) where
168        Self: Sized,
169    {
170        self.0.to_html_async_with_buf::<OUT_OF_ORDER>(
171            buf,
172            position,
173            escape,
174            mark_branches,
175            extra_attrs,
176        );
177    }
178
179    fn hydrate<const FROM_SERVER: bool>(
180        self,
181        cursor: &Cursor,
182        position: &PositionState,
183    ) -> Self::State {
184        self.0.hydrate::<FROM_SERVER>(cursor, position)
185    }
186
187    async fn hydrate_async(
188        self,
189        cursor: &Cursor,
190        position: &PositionState,
191    ) -> Self::State {
192        self.0.hydrate_async(cursor, position).await
193    }
194
195    async fn resolve(self) -> Self::AsyncOutput {
196        (self.0.resolve().await,)
197    }
198
199    fn dry_resolve(&mut self) {
200        self.0.dry_resolve();
201    }
202
203    fn into_owned(self) -> Self::Owned {
204        (self.0.into_owned(),)
205    }
206}
207
208impl<A: ToTemplate> ToTemplate for (A,) {
209    const TEMPLATE: &'static str = A::TEMPLATE;
210    const CLASS: &'static str = A::CLASS;
211    const STYLE: &'static str = A::STYLE;
212
213    fn to_template(
214        buf: &mut String,
215        class: &mut String,
216        style: &mut String,
217        inner_html: &mut String,
218        position: &mut Position,
219    ) {
220        A::to_template(buf, class, style, inner_html, position)
221    }
222}
223
224impl<A> AddAnyAttr for (A,)
225where
226    A: AddAnyAttr,
227{
228    type Output<SomeNewAttr: Attribute> = (A::Output<SomeNewAttr>,);
229
230    fn add_any_attr<NewAttr: Attribute>(
231        self,
232        attr: NewAttr,
233    ) -> Self::Output<NewAttr>
234    where
235        Self::Output<NewAttr>: RenderHtml,
236    {
237        (self.0.add_any_attr(attr),)
238    }
239}
240
241macro_rules! impl_view_for_tuples {
242	($first:ident, $($ty:ident),* $(,)?) => {
243		impl<$first, $($ty),*> Render for ($first, $($ty,)*)
244		where
245			$first: Render,
246			$($ty: Render),*,
247
248		{
249			type State = ($first::State, $($ty::State,)*);
250
251			fn build(self) -> Self::State {
252                #[allow(non_snake_case)]
253                let ($first, $($ty,)*) = self;
254                (
255                    $first.build(),
256                    $($ty.build()),*
257                )
258			}
259
260			fn rebuild(self, state: &mut Self::State) {
261				paste::paste! {
262					let ([<$first:lower>], $([<$ty:lower>],)*) = self;
263					let ([<view_ $first:lower>], $([<view_ $ty:lower>],)*) = state;
264					[<$first:lower>].rebuild([<view_ $first:lower>]);
265					$([<$ty:lower>].rebuild([<view_ $ty:lower>]));*
266				}
267			}
268		}
269
270		impl<$first, $($ty),*> RenderHtml for ($first, $($ty,)*)
271		where
272			$first: RenderHtml,
273			$($ty: RenderHtml),*,
274
275		{
276            type AsyncOutput = ($first::AsyncOutput, $($ty::AsyncOutput,)*);
277            type Owned = ($first::Owned, $($ty::Owned,)*);
278            const EXISTS: bool = $first::EXISTS || $($ty::EXISTS || )* false;
279            const MIN_LENGTH: usize = $first::MIN_LENGTH $(+ $ty::MIN_LENGTH)*;
280
281            #[inline(always)]
282            fn html_len(&self) -> usize {
283                #[allow(non_snake_case)]
284			    let ($first, $($ty,)* ) = self;
285                $($ty.html_len() +)* $first.html_len()
286            }
287
288			fn to_html_with_buf(
289                self,
290                buf: &mut String,
291                position: &mut Position,
292                escape: bool,
293                mark_branches: bool,
294                extra_attrs: Vec<AnyAttribute>
295            ) {
296                #[allow(non_snake_case)]
297                let ($first, $($ty,)* ) = self;
298                $first.to_html_with_buf(buf, position, escape, mark_branches, extra_attrs.clone());
299                $($ty.to_html_with_buf(buf, position, escape, mark_branches, extra_attrs.clone()));*
300			}
301
302			fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
303				self,
304				buf: &mut StreamBuilder,
305                position: &mut Position,
306                escape: bool,
307                mark_branches: bool,
308                extra_attrs: Vec<AnyAttribute>
309            ) where
310				Self: Sized,
311			{
312                #[allow(non_snake_case)]
313                let ($first, $($ty,)* ) = self;
314                $first.to_html_async_with_buf::<OUT_OF_ORDER>(buf, position, escape, mark_branches, extra_attrs.clone());
315                $($ty.to_html_async_with_buf::<OUT_OF_ORDER>(buf, position, escape, mark_branches, extra_attrs.clone()));*
316			}
317
318			fn hydrate<const FROM_SERVER: bool>(self, cursor: &Cursor, position: &PositionState) -> Self::State {
319                #[allow(non_snake_case)]
320					let ($first, $($ty,)* ) = self;
321					(
322						$first.hydrate::<FROM_SERVER>(cursor, position),
323						$($ty.hydrate::<FROM_SERVER>(cursor, position)),*
324					)
325			}
326
327            async fn hydrate_async(self, cursor: &Cursor, position: &PositionState) -> Self::State {
328                #[allow(non_snake_case)]
329					let ($first, $($ty,)* ) = self;
330					(
331						$first.hydrate_async(cursor, position).await,
332						$($ty.hydrate_async(cursor, position).await),*
333					)
334			}
335
336            async fn resolve(self) -> Self::AsyncOutput {
337                #[allow(non_snake_case)]
338                let ($first, $($ty,)*) = self;
339                futures::join!(
340                    $first.resolve(),
341                    $($ty.resolve()),*
342                )
343            }
344
345            fn dry_resolve(&mut self) {
346                #[allow(non_snake_case)]
347                let ($first, $($ty,)*) = self;
348                $first.dry_resolve();
349                $($ty.dry_resolve());*
350            }
351
352            fn into_owned(self) -> Self::Owned {
353                #[allow(non_snake_case)]
354                let ($first, $($ty,)*) = self;
355                (
356                    $first.into_owned(),
357                    $($ty.into_owned()),*
358                )
359            }
360		}
361
362		impl<$first, $($ty),*> ToTemplate for ($first, $($ty,)*)
363		where
364			$first: ToTemplate,
365			$($ty: ToTemplate),*
366		{
367			const TEMPLATE: &'static str = str_from_buffer(&const_concat(&[
368				$first::TEMPLATE, $($ty::TEMPLATE),*
369			]));
370			const CLASS: &'static str = str_from_buffer(&const_concat_with_separator(&[
371				$first::CLASS, $($ty::CLASS),*
372			], " "));
373			const STYLE: &'static str = str_from_buffer(&const_concat_with_separator(&[
374				$first::STYLE, $($ty::STYLE),*
375			], ";"));
376
377			fn to_template(buf: &mut String, class: &mut String, style: &mut String, inner_html: &mut String, position: &mut Position)  {
378                $first ::to_template(buf, class, style, inner_html, position);
379                $($ty::to_template(buf, class, style, inner_html, position));*;
380			}
381		}
382
383		impl<$first, $($ty),*> Mountable for ($first, $($ty,)*) where
384			$first: Mountable,
385			$($ty: Mountable),*,
386
387		{
388			fn unmount(&mut self) {
389                #[allow(non_snake_case)] // better macro performance
390                let ($first, $($ty,)*) = self;
391                $first.unmount();
392                $($ty.unmount());*
393			}
394
395			fn mount(
396				&mut self,
397				parent: &crate::renderer::types::Element,
398				marker: Option<&crate::renderer::types::Node>,
399			) {
400                #[allow(non_snake_case)] // better macro performance
401                let ($first, $($ty,)*) = self;
402                $first.mount(parent, marker);
403                $($ty.mount(parent, marker));*
404			}
405
406			fn insert_before_this(&self,
407				child: &mut dyn Mountable,
408			) -> bool {
409                #[allow(non_snake_case)] // better macro performance
410                let ($first, $($ty,)*) = self;
411                $first.insert_before_this(child)
412                $(|| $ty.insert_before_this(child))*
413			}
414
415            fn elements(&self) -> Vec<crate::renderer::types::Element> {
416                #[allow(non_snake_case)] // better macro performance
417                let ($first, $($ty,)*) = self;
418                $first.elements().into_iter()
419                $(.chain($ty.elements()))*
420                    .collect()
421            }
422		}
423
424        impl<$first, $($ty,)*> AddAnyAttr for ($first, $($ty,)*)
425        where
426			$first: AddAnyAttr,
427			$($ty: AddAnyAttr),*,
428
429        {
430            type Output<SomeNewAttr: Attribute> = ($first::Output<SomeNewAttr::Cloneable>, $($ty::Output<SomeNewAttr::Cloneable>,)*);
431
432            fn add_any_attr<NewAttr: Attribute>(
433                self,
434                attr: NewAttr,
435            ) -> Self::Output<NewAttr>
436            where
437                Self::Output<NewAttr>: RenderHtml,
438            {
439                let shared = attr.into_cloneable();
440                #[allow(non_snake_case)] // better macro performance
441                let ($first, $($ty,)*) = self;
442                ($first.add_any_attr(shared.clone()), $($ty.add_any_attr(shared.clone()),)*)
443            }
444        }
445    };
446}
447
448impl_view_for_tuples!(A, B);
449impl_view_for_tuples!(A, B, C);
450impl_view_for_tuples!(A, B, C, D);
451impl_view_for_tuples!(A, B, C, D, E);
452impl_view_for_tuples!(A, B, C, D, E, F);
453impl_view_for_tuples!(A, B, C, D, E, F, G);
454impl_view_for_tuples!(A, B, C, D, E, F, G, H);
455impl_view_for_tuples!(A, B, C, D, E, F, G, H, I);
456impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J);
457impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K);
458impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K, L);
459impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M);
460impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
461impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
462impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
463impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
464impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
465impl_view_for_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
466impl_view_for_tuples!(
467    A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T
468);
469impl_view_for_tuples!(
470    A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U
471);
472impl_view_for_tuples!(
473    A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V
474);
475impl_view_for_tuples!(
476    A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W
477);
478impl_view_for_tuples!(
479    A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X
480);
481impl_view_for_tuples!(
482    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
483);
484impl_view_for_tuples!(
485    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,
486    Z
487);