use crate::dom::{
element::ElementRef,
node::{Node, NodeRef},
};
pub trait NodeList {
type Output: Node;
fn item(&self, index: usize) -> Option<Self::Output>;
fn length(&self) -> usize;
}
pub struct ChildNodesList<N: Node> {
owner_node: N,
}
impl<N: Node> ChildNodesList<N> {
pub(super) fn new(owner_node: N) -> Self {
Self { owner_node }
}
}
impl<N: Node> NodeList for ChildNodesList<N> {
type Output = NodeRef;
fn item(&self, index: usize) -> Option<Self::Output> {
let mut children = self.owner_node.first_child();
let mut now = 0;
while let Some(child) = children {
if now == index {
return Some(child);
}
now += 1;
children = child.next_sibling();
}
None
}
fn length(&self) -> usize {
let mut children = self.owner_node.first_child();
let mut cnt = 0;
while let Some(child) = children {
cnt += 1;
children = child.next_sibling();
}
cnt
}
}
pub struct FilteredSubtreeElementsList {
root: NodeRef,
namespace_uri: Option<String>,
local_name: String,
eq: fn(ElementRef, Option<&str>, &str) -> bool,
}
impl FilteredSubtreeElementsList {
pub(super) fn new(
root: NodeRef,
namespace_uri: Option<String>,
local_name: String,
eq: fn(ElementRef, Option<&str>, &str) -> bool,
) -> Self {
Self {
root,
namespace_uri,
local_name,
eq,
}
}
fn seek(
&self,
index: usize,
eq: impl Fn(ElementRef, Option<&str>, &str) -> bool,
) -> Result<ElementRef, usize> {
let mut descendant = self.root.first_child();
let mut cnt = 0;
while let Some(mut now) = descendant.filter(|dsc| !self.root.is_same_node(dsc)) {
if let Some(elem) = now.as_element().filter(|elem| {
eq(
elem.clone(),
self.namespace_uri.as_deref(),
&self.local_name,
)
}) {
if cnt == index {
return Ok(elem);
}
cnt += 1;
}
if let Some(child) = now.first_child() {
descendant = Some(child);
} else if let Some(sibling) = now.next_sibling() {
descendant = Some(sibling);
} else {
descendant = None;
while let Some(par) = now
.parent_node()
.filter(|par| !par.is_same_node(&self.root))
{
if let Some(sibling) = par.next_sibling() {
descendant = Some(sibling);
break;
}
now = par;
}
}
}
Err(cnt)
}
}
impl NodeList for FilteredSubtreeElementsList {
type Output = ElementRef;
fn item(&self, index: usize) -> Option<Self::Output> {
self.seek(index, self.eq).ok()
}
fn length(&self) -> usize {
self.seek(usize::MAX, self.eq).err().unwrap_or(usize::MAX)
}
}