diff --git a/tachys/src/view/iterators.rs b/tachys/src/view/iterators.rs index 97ac2d6ab..32efde525 100644 --- a/tachys/src/view/iterators.rs +++ b/tachys/src/view/iterators.rs @@ -336,3 +336,147 @@ 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::() + } + + 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); + } + } + + 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, + ); + } + } + + fn hydrate( + self, + cursor: &Cursor, + position: &PositionState, + ) -> Self::State { + let states = + self.map(|child| child.hydrate::(cursor, position)); + ArrayState { states } + } +}