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)] 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)] 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)] 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)] 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)] 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);