use crate::vdom::TreePath;
#[derive(Debug, PartialEq, Clone)]
pub enum SkipAttrs {
All,
Indices(Vec<usize>),
}
impl SkipAttrs {
pub fn none() -> Self {
Self::Indices(vec![])
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct SkipDiff {
pub skip_attrs: SkipAttrs,
pub children: Vec<SkipDiff>,
}
impl SkipDiff {
pub fn block() -> Self {
Self {
skip_attrs: SkipAttrs::none(),
children: vec![],
}
}
pub fn in_path(&self, path: &TreePath) -> Option<&Self> {
let mut path = path.clone();
if path.is_empty() {
Some(self)
} else {
let idx = path.remove_first();
if let Some(child) = self.children.get(idx) {
child.in_path(&path)
} else {
None
}
}
}
pub fn traverse(&self, idx: usize) -> Option<&Self> {
self.children.get(idx)
}
pub fn shall_skip_attributes(&self) -> bool {
self.skip_attrs == SkipAttrs::All
}
pub fn is_skippable_recursive(&self) -> bool {
self.shall_skip_attributes() && self.children.iter().all(Self::is_skippable_recursive)
}
pub fn shall_skip_node(&self) -> bool {
self.shall_skip_attributes() && self.children.is_empty()
}
pub fn collapse_children(self) -> Self {
let Self {
skip_attrs,
children,
} = self;
let can_skip_children = children.iter().all(Self::is_skippable_recursive);
Self {
skip_attrs,
children: if can_skip_children {
vec![]
} else {
children.into_iter().map(Self::collapse_children).collect()
},
}
}
}
pub fn skip_if(shall: bool, children: impl IntoIterator<Item = SkipDiff>) -> SkipDiff {
SkipDiff {
skip_attrs: if shall {
SkipAttrs::All
} else {
SkipAttrs::none()
},
children: children.into_iter().collect(),
}
}
#[derive(Debug)]
pub struct SkipPath {
pub(crate) path: TreePath,
pub(crate) skip_diff: Option<SkipDiff>,
}
impl SkipPath {
pub(crate) fn new(path: TreePath, skip_diff: SkipDiff) -> Self {
Self {
path,
skip_diff: Some(skip_diff),
}
}
pub(crate) fn traverse(&self, idx: usize) -> Self {
Self {
path: self.path.traverse(idx),
skip_diff: if let Some(skip_diff) = self.skip_diff.as_ref() {
skip_diff.traverse(idx).cloned()
} else {
None
},
}
}
pub(crate) fn backtrack(&self) -> Self {
Self {
path: self.path.backtrack(),
skip_diff: None,
}
}
}