1use self::add_attr::AddAnyAttr;
2use crate::{
3 html::attribute::any_attribute::AnyAttribute, hydration::Cursor,
4 ssr::StreamBuilder,
5};
6use parking_lot::RwLock;
7use std::{cell::RefCell, future::Future, rc::Rc, sync::Arc};
8
9pub mod add_attr;
11pub mod any_view;
13pub mod either;
15pub mod error_boundary;
17pub mod fragment;
19pub mod iterators;
21pub mod keyed;
23mod primitives;
24#[cfg(all(feature = "nightly", rustc_nightly))]
26pub mod static_types;
27pub mod strings;
29pub mod template;
31pub mod tuples;
33
34pub trait Render: Sized {
36 type State: Mountable;
41
42 fn build(self) -> Self::State;
44
45 fn rebuild(self, state: &mut Self::State);
47}
48
49#[doc(hidden)]
50pub trait MarkBranch {
51 fn open_branch(&mut self, branch_id: &str);
52
53 fn close_branch(&mut self, branch_id: &str);
54}
55
56impl MarkBranch for String {
57 fn open_branch(&mut self, branch_id: &str) {
58 self.push_str("<!--bo-");
59 self.push_str(branch_id);
60 self.push_str("-->");
61 }
62
63 fn close_branch(&mut self, branch_id: &str) {
64 self.push_str("<!--bc-");
65 self.push_str(branch_id);
66 self.push_str("-->");
67 }
68}
69
70impl MarkBranch for StreamBuilder {
71 fn open_branch(&mut self, branch_id: &str) {
72 self.sync_buf.push_str("<!--bo-");
73 self.sync_buf.push_str(branch_id);
74 self.sync_buf.push_str("-->");
75 }
76
77 fn close_branch(&mut self, branch_id: &str) {
78 self.sync_buf.push_str("<!--bc-");
79 self.sync_buf.push_str(branch_id);
80 self.sync_buf.push_str("-->");
81 }
82}
83
84pub trait RenderHtml
97where
98 Self: Render + AddAnyAttr + Send,
99{
100 type AsyncOutput: RenderHtml;
102
103 type Owned: RenderHtml + 'static;
105
106 const MIN_LENGTH: usize;
108
109 const EXISTS: bool = true;
111
112 fn dry_resolve(&mut self);
116
117 fn resolve(self) -> impl Future<Output = Self::AsyncOutput> + Send;
119
120 fn html_len(&self) -> usize {
126 Self::MIN_LENGTH
127 }
128
129 fn to_html(self) -> String
131 where
132 Self: Sized,
133 {
134 let mut buf = String::with_capacity(self.html_len());
135 self.to_html_with_buf(
136 &mut buf,
137 &mut Position::FirstChild,
138 true,
139 false,
140 vec![],
141 );
142 buf
143 }
144
145 fn to_html_branching(self) -> String
149 where
150 Self: Sized,
151 {
152 let mut buf = String::with_capacity(self.html_len());
153 self.to_html_with_buf(
154 &mut buf,
155 &mut Position::FirstChild,
156 true,
157 true,
158 vec![],
159 );
160 buf
161 }
162
163 fn to_html_stream_in_order(self) -> StreamBuilder
165 where
166 Self: Sized,
167 {
168 let mut builder = StreamBuilder::with_capacity(self.html_len(), None);
169 self.to_html_async_with_buf::<false>(
170 &mut builder,
171 &mut Position::FirstChild,
172 true,
173 false,
174 vec![],
175 );
176 builder.finish()
177 }
178
179 fn to_html_stream_in_order_branching(self) -> StreamBuilder
183 where
184 Self: Sized,
185 {
186 let mut builder = StreamBuilder::with_capacity(self.html_len(), None);
187 self.to_html_async_with_buf::<false>(
188 &mut builder,
189 &mut Position::FirstChild,
190 true,
191 true,
192 vec![],
193 );
194 builder.finish()
195 }
196
197 fn to_html_stream_out_of_order(self) -> StreamBuilder
199 where
200 Self: Sized,
201 {
202 let mut builder =
204 StreamBuilder::with_capacity(self.html_len(), Some(vec![0]));
205
206 self.to_html_async_with_buf::<true>(
207 &mut builder,
208 &mut Position::FirstChild,
209 true,
210 false,
211 vec![],
212 );
213 builder.finish()
214 }
215
216 fn to_html_stream_out_of_order_branching(self) -> StreamBuilder
220 where
221 Self: Sized,
222 {
223 let mut builder =
224 StreamBuilder::with_capacity(self.html_len(), Some(vec![0]));
225
226 self.to_html_async_with_buf::<true>(
227 &mut builder,
228 &mut Position::FirstChild,
229 true,
230 true,
231 vec![],
232 );
233 builder.finish()
234 }
235
236 fn to_html_with_buf(
238 self,
239 buf: &mut String,
240 position: &mut Position,
241 escape: bool,
242 mark_branches: bool,
243 extra_attrs: Vec<AnyAttribute>,
244 );
245
246 fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
248 self,
249 buf: &mut StreamBuilder,
250 position: &mut Position,
251 escape: bool,
252 mark_branches: bool,
253 extra_attrs: Vec<AnyAttribute>,
254 ) where
255 Self: Sized,
256 {
257 buf.with_buf(|buf| {
258 self.to_html_with_buf(
259 buf,
260 position,
261 escape,
262 mark_branches,
263 extra_attrs,
264 )
265 });
266 }
267
268 fn hydrate<const FROM_SERVER: bool>(
276 self,
277 cursor: &Cursor,
278 position: &PositionState,
279 ) -> Self::State;
280
281 fn hydrate_async(
287 self,
288 cursor: &Cursor,
289 position: &PositionState,
290 ) -> impl Future<Output = Self::State> {
291 async { self.hydrate::<true>(cursor, position) }
292 }
293
294 fn hydrate_from<const FROM_SERVER: bool>(
296 self,
297 el: &crate::renderer::types::Element,
298 ) -> Self::State
299 where
300 Self: Sized,
301 {
302 self.hydrate_from_position::<FROM_SERVER>(el, Position::default())
303 }
304
305 fn hydrate_from_position<const FROM_SERVER: bool>(
307 self,
308 el: &crate::renderer::types::Element,
309 position: Position,
310 ) -> Self::State
311 where
312 Self: Sized,
313 {
314 let cursor = Cursor::new(el.clone());
315 let position = PositionState::new(position);
316 self.hydrate::<FROM_SERVER>(&cursor, &position)
317 }
318
319 fn into_owned(self) -> Self::Owned;
321}
322
323pub trait Mountable {
325 fn unmount(&mut self);
327
328 fn mount(
330 &mut self,
331 parent: &crate::renderer::types::Element,
332 marker: Option<&crate::renderer::types::Node>,
333 );
334
335 fn try_mount(
337 &mut self,
338 parent: &crate::renderer::types::Element,
339 marker: Option<&crate::renderer::types::Node>,
340 ) -> bool {
341 self.mount(parent, marker);
342 true
343 }
344
345 fn insert_before_this(&self, child: &mut dyn Mountable) -> bool;
348
349 fn insert_before_this_or_marker(
352 &self,
353 parent: &crate::renderer::types::Element,
354 child: &mut dyn Mountable,
355 marker: Option<&crate::renderer::types::Node>,
356 ) {
357 if !self.insert_before_this(child) {
358 child.mount(parent, marker);
359 }
360 }
361
362 fn elements(&self) -> Vec<crate::renderer::types::Element>;
364}
365
366pub enum MountKind {
368 Before(crate::renderer::types::Node),
370 Append,
372}
373
374impl<T> Mountable for Option<T>
375where
376 T: Mountable,
377{
378 fn unmount(&mut self) {
379 if let Some(ref mut mounted) = self {
380 mounted.unmount()
381 }
382 }
383
384 fn mount(
385 &mut self,
386 parent: &crate::renderer::types::Element,
387 marker: Option<&crate::renderer::types::Node>,
388 ) {
389 if let Some(ref mut inner) = self {
390 inner.mount(parent, marker);
391 }
392 }
393
394 fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
395 self.as_ref()
396 .map(|inner| inner.insert_before_this(child))
397 .unwrap_or(false)
398 }
399
400 fn elements(&self) -> Vec<crate::renderer::types::Element> {
401 self.as_ref()
402 .map(|inner| inner.elements())
403 .unwrap_or_default()
404 }
405}
406
407impl<T> Mountable for Rc<RefCell<T>>
408where
409 T: Mountable,
410{
411 fn unmount(&mut self) {
412 self.borrow_mut().unmount()
413 }
414
415 fn mount(
416 &mut self,
417 parent: &crate::renderer::types::Element,
418 marker: Option<&crate::renderer::types::Node>,
419 ) {
420 self.borrow_mut().mount(parent, marker);
421 }
422
423 fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
424 self.borrow().insert_before_this(child)
425 }
426
427 fn elements(&self) -> Vec<crate::renderer::types::Element> {
428 self.borrow().elements()
429 }
430}
431
432pub trait ToTemplate {
434 const TEMPLATE: &'static str = "";
436 const CLASS: &'static str = "";
438 const STYLE: &'static str = "";
440 const LEN: usize = Self::TEMPLATE.len();
442
443 fn to_template(
447 buf: &mut String,
448 class: &mut String,
449 style: &mut String,
450 inner_html: &mut String,
451 position: &mut Position,
452 );
453
454 fn to_template_attribute(
456 buf: &mut String,
457 class: &mut String,
458 style: &mut String,
459 inner_html: &mut String,
460 position: &mut Position,
461 ) {
462 Self::to_template(buf, class, style, inner_html, position);
463 }
464}
465
466#[derive(Debug, Default, Clone)]
469pub struct PositionState(Arc<RwLock<Position>>);
470
471impl PositionState {
472 pub fn new(position: Position) -> Self {
474 Self(Arc::new(RwLock::new(position)))
475 }
476
477 pub fn set(&self, position: Position) {
479 *self.0.write() = position;
480 }
481
482 pub fn get(&self) -> Position {
484 *self.0.read()
485 }
486
487 pub fn deep_clone(&self) -> Self {
490 let current = self.get();
491 Self(Arc::new(RwLock::new(current)))
492 }
493}
494
495#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
497pub enum Position {
498 Current,
500 #[default]
502 FirstChild,
503 NextChild,
505 NextChildAfterText,
507 OnlyChild,
509 LastChild,
511}
512
513pub trait IntoRender {
515 type Output;
517
518 fn into_render(self) -> Self::Output;
520}
521
522impl<T> IntoRender for T
523where
524 T: Render,
525{
526 type Output = Self;
527
528 fn into_render(self) -> Self::Output {
529 self
530 }
531}