feat: implement rendering traits for fixed-size arrays (#3174)

This commit is contained in:
Louis Dispa 2024-11-04 18:26:43 +01:00 committed by GitHub
parent 3a8508df6c
commit d9f52dad76
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -336,3 +336,147 @@ where
VecState { states, marker }
}
}
impl<T, const N: usize> Render for [T; N]
where
T: Render,
{
type State = ArrayState<T::State, N>;
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<T, const N: usize>
where
T: Mountable,
{
states: [T; N],
}
impl<T, const N: usize> Mountable for ArrayState<T, N>
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<T, const N: usize> AddAnyAttr for [T; N]
where
T: AddAnyAttr,
{
type Output<SomeNewAttr: Attribute> =
[<T as AddAnyAttr>::Output<SomeNewAttr::Cloneable>; N];
fn add_any_attr<NewAttr: Attribute>(
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml,
{
let attr = attr.into_cloneable();
self.map(|n| n.add_any_attr(attr.clone()))
}
}
impl<T, const N: usize> 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::<Vec<_>>()
.try_into()
.unwrap_or_else(|_| unreachable!())
}
fn html_len(&self) -> usize {
self.iter().map(RenderHtml::html_len).sum::<usize>()
}
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<const OUT_OF_ORDER: bool>(
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::<OUT_OF_ORDER>(
buf,
position,
escape,
mark_branches,
);
}
}
fn hydrate<const FROM_SERVER: bool>(
self,
cursor: &Cursor,
position: &PositionState,
) -> Self::State {
let states =
self.map(|child| child.hydrate::<FROM_SERVER>(cursor, position));
ArrayState { states }
}
}