use ebml_iterable_specification::{EbmlSpecification, EbmlTag, PathPart};
use crate::tag_iterator_util::EBMLSize;
pub fn is_parent<T: EbmlSpecification<T> + EbmlTag<T> + Clone>(current_id: u64, test_id: u64) -> bool {
let path = <T>::get_path_by_id(current_id);
path.iter().any(|p| matches!(p, PathPart::Id(p) if p == &test_id))
}
pub fn is_sibling<T: EbmlSpecification<T> + EbmlTag<T> + Clone>(current_id: u64, test_id: u64) -> bool {
<T>::get_path_by_id(current_id) == <T>::get_path_by_id(test_id)
}
pub fn is_ended_by<T: EbmlSpecification<T> + EbmlTag<T> + Clone>(current_id: u64, test_id: u64) -> bool {
is_parent::<T>(current_id, test_id) || is_sibling::<T>(current_id, test_id) || ( <T>::get_tag_data_type(test_id).is_some() &&
<T>::get_path_by_id(test_id).is_empty()
)
}
#[inline(always)]
pub fn validate_tag_path<T: EbmlSpecification<T> + EbmlTag<T> + Clone>(tag_id: u64, doc_path: impl Iterator<Item = (u64, EBMLSize, usize)>) -> bool {
let path = <T>::get_path_by_id(tag_id);
let mut path_marker = 0;
let mut global_counter = 0;
for item in doc_path {
let current_node_id = item.0;
if !item.1.is_known() && is_ended_by::<T>(current_node_id, tag_id) {
return true;
}
if path_marker >= path.len() {
return false;
}
match path[path_marker] {
PathPart::Id(id) => {
if id != current_node_id {
return false;
}
path_marker += 1;
},
PathPart::Global((min, max)) => {
global_counter += 1;
if max.is_some() && global_counter > max.unwrap_or_default() {
return false;
}
if path.len() > (path_marker + 1) && matches!(path[path_marker + 1], PathPart::Id(id) if id == current_node_id) {
if min.is_some() && global_counter < min.unwrap_or_default() {
return false;
}
path_marker += 2;
global_counter = 0;
}
},
}
}
path.len() == path_marker ||
((path.len() - 1) == path_marker && matches!(path[path_marker], PathPart::Global((min, _)) if global_counter >= min.unwrap_or(0)))
}