#![allow(clippy::too_many_arguments)]
use crate::{
arena::ElementId,
innerlude::{ElementRef, MountId, WriteMutations},
nodes::VNode,
scopes::ScopeId,
virtual_dom::VirtualDom,
Template, TemplateNode,
};
mod component;
mod iterator;
mod node;
impl VirtualDom {
pub(crate) fn create_children<'a>(
&mut self,
to: &mut impl WriteMutations,
nodes: impl IntoIterator<Item = &'a VNode>,
parent: Option<ElementRef>,
) -> usize {
nodes
.into_iter()
.map(|child| child.create(self, to, parent))
.sum()
}
fn replace_placeholder<'a>(
&mut self,
to: &mut impl WriteMutations,
placeholder_id: ElementId,
r: impl IntoIterator<Item = &'a VNode>,
parent: Option<ElementRef>,
) {
let m = self.create_children(to, r, parent);
to.replace_node_with(placeholder_id, m);
self.reclaim(placeholder_id);
}
fn nodes_to_placeholder(
&mut self,
to: &mut impl WriteMutations,
mount: MountId,
dyn_node_idx: usize,
old_nodes: &[VNode],
) {
let placeholder = self.next_element();
self.mounts[mount.0].mounted_dynamic_nodes[dyn_node_idx] = placeholder.0;
to.create_placeholder(placeholder);
self.replace_nodes(to, old_nodes, 1);
}
fn replace_nodes(&mut self, to: &mut impl WriteMutations, nodes: &[VNode], m: usize) {
debug_assert!(
!nodes.is_empty(),
"replace_nodes must have at least one node"
);
self.remove_nodes(to, nodes, Some(m));
}
fn remove_nodes(
&mut self,
to: &mut impl WriteMutations,
nodes: &[VNode],
replace_with: Option<usize>,
) {
for (i, node) in nodes.iter().rev().enumerate() {
let last_node = i == nodes.len() - 1;
node.remove_node(self, to, replace_with.filter(|_| last_node), true);
}
}
pub(crate) fn remove_component_node(
&mut self,
to: &mut impl WriteMutations,
scope: ScopeId,
replace_with: Option<usize>,
gen_muts: bool,
) {
if let Some(node) = self.scopes[scope.0].last_rendered_node.take() {
node.remove_node(self, to, replace_with, gen_muts)
};
self.drop_scope(scope);
}
#[allow(unused_mut)]
pub(crate) fn register_template(
&mut self,
to: &mut impl WriteMutations,
mut template: Template,
) {
let (path, byte_index) = template.name.rsplit_once(':').unwrap();
let byte_index = byte_index.parse::<usize>().unwrap();
if self
.templates
.get(&path)
.filter(|set| set.contains_key(&byte_index))
.is_none()
{
#[cfg(debug_assertions)]
if let Some(mut new_template) = self
.templates
.get_mut(path)
.and_then(|map| map.remove(&usize::MAX))
{
new_template.name = template.name;
template = new_template;
}
self.templates
.entry(path)
.or_default()
.insert(byte_index, template);
if !template.is_completely_dynamic() {
to.register_template(template)
}
}
}
pub(crate) fn register_template_first_byte_index(&mut self, mut template: Template) {
let (path, _) = template.name.rsplit_once(':').unwrap();
if let Some((_, old_template)) = self
.templates
.entry(path)
.or_default()
.iter_mut()
.min_by_key(|(byte_index, _)| **byte_index)
{
template.name = old_template.name;
*old_template = template;
} else {
self.templates
.entry(path)
.or_default()
.insert(usize::MAX, template);
}
if !template.is_completely_dynamic() {
self.queued_templates.push(template);
}
}
}
#[allow(dead_code)]
fn is_dyn_node_only_child(node: &VNode, idx: usize) -> bool {
let template = node.template.get();
let path = template.node_paths[idx];
let mut static_node = &template.roots[path[0] as usize];
for i in 1..path.len() - 1 {
match static_node {
TemplateNode::Element { children, .. } => static_node = &children[path[i] as usize],
_ => return false,
}
}
match static_node {
TemplateNode::Element { children, .. } => children.len() == 1,
_ => false,
}
}