From edf38915bed99237de27dca6b0a7c1e9c3a8e5d0 Mon Sep 17 00:00:00 2001 From: Louis Dispa Date: Tue, 29 Oct 2024 22:34:11 +0100 Subject: [PATCH 1/2] feat: add array rendering --- tachys/src/view/iterators.rs | 146 +++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) diff --git a/tachys/src/view/iterators.rs b/tachys/src/view/iterators.rs index 97ac2d6ab8..ef745412e4 100644 --- a/tachys/src/view/iterators.rs +++ b/tachys/src/view/iterators.rs @@ -336,3 +336,149 @@ where VecState { states, marker } } } + +impl Render for [T; N] +where + T: Render, +{ + type State = ArrayState; + + fn build(self) -> Self::State { + Self::State { + states: self.map(T::build), + } + } + + fn rebuild(self, state: &mut Self::State) { + let Self::State { states } = state; + let old = states; + // this is an unkeyed diff + self.into_iter() + .zip(old.iter_mut()) + .for_each(|(new, old)| T::rebuild(new, old)); + } +} + +/// Retained view state for a `Vec<_>`. +pub struct ArrayState +where + T: Mountable, +{ + states: [T; N], +} + +impl Mountable for ArrayState +where + T: Mountable, +{ + fn unmount(&mut self) { + self.states.iter_mut().for_each(Mountable::unmount); + } + + fn mount( + &mut self, + parent: &crate::renderer::types::Element, + marker: Option<&crate::renderer::types::Node>, + ) { + for state in self.states.iter_mut() { + state.mount(parent, marker); + } + } + + fn insert_before_this(&self, child: &mut dyn Mountable) -> bool { + if let Some(first) = self.states.first() { + first.insert_before_this(child) + } else { + false + } + } +} +impl AddAnyAttr for [T; N] +where + T: AddAnyAttr, +{ + type Output = + [::Output; N]; + + fn add_any_attr( + self, + attr: NewAttr, + ) -> Self::Output + where + Self::Output: RenderHtml, + { + let attr = attr.into_cloneable(); + self.map(|n| n.add_any_attr(attr.clone())) + } +} + +impl RenderHtml for [T; N] +where + T: RenderHtml, +{ + type AsyncOutput = [T::AsyncOutput; N]; + + const MIN_LENGTH: usize = 0; + + fn dry_resolve(&mut self) { + for inner in self.iter_mut() { + inner.dry_resolve(); + } + } + + async fn resolve(self) -> Self::AsyncOutput { + futures::future::join_all(self.into_iter().map(T::resolve)) + .await + .into_iter() + .collect::>() + .try_into() + .unwrap_or_else(|_| unreachable!()) + } + + fn html_len(&self) -> usize { + self.iter().map(RenderHtml::html_len).sum::() + 2 + } + + fn to_html_with_buf( + self, + buf: &mut String, + position: &mut Position, + escape: bool, + mark_branches: bool, + ) { + for child in self.into_iter() { + child.to_html_with_buf(buf, position, escape, mark_branches); + } + buf.push_str(""); + } + + fn to_html_async_with_buf( + self, + buf: &mut StreamBuilder, + position: &mut Position, + escape: bool, + mark_branches: bool, + ) where + Self: Sized, + { + for child in self.into_iter() { + child.to_html_async_with_buf::( + buf, + position, + escape, + mark_branches, + ); + } + buf.push_sync(""); + } + + fn hydrate( + self, + cursor: &Cursor, + position: &PositionState, + ) -> Self::State { + let states = + self.map(|child| child.hydrate::(cursor, position)); + ArrayState { states } + } +} From 5b06b06e311c55832810e09b414726dbbb0a8ae5 Mon Sep 17 00:00:00 2001 From: Greg Johnston Date: Sun, 3 Nov 2024 20:07:55 -0500 Subject: [PATCH 2/2] remove placeholder insert in SSR --- tachys/src/view/iterators.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tachys/src/view/iterators.rs b/tachys/src/view/iterators.rs index ef745412e4..32efde5252 100644 --- a/tachys/src/view/iterators.rs +++ b/tachys/src/view/iterators.rs @@ -436,7 +436,7 @@ where } fn html_len(&self) -> usize { - self.iter().map(RenderHtml::html_len).sum::() + 2 + self.iter().map(RenderHtml::html_len).sum::() } fn to_html_with_buf( @@ -449,7 +449,6 @@ where for child in self.into_iter() { child.to_html_with_buf(buf, position, escape, mark_branches); } - buf.push_str(""); } fn to_html_async_with_buf( @@ -469,7 +468,6 @@ where mark_branches, ); } - buf.push_sync(""); } fn hydrate(