use std::fmt;
use html5ever::rcdom::Handle;
use crate::{
Soup,
find::{AttrQuery, QueryBuilder, QueryWrapper, TagQuery},
pattern::Pattern,
};
pub trait QueryBuilderExt {
fn get_handle(&self) -> Handle;
fn limit<'a>(&self, limit: usize) -> QueryBuilder<'a, (), ()> {
let handle = self.get_handle();
let qb = QueryBuilder::new(handle);
qb.limit(limit)
}
fn tag<'a, P: Pattern>(
&self,
tag: P,
) -> QueryBuilder<'a, TagQuery<P>, QueryWrapper<'a, (), ()>> {
let handle = self.get_handle();
let qb = QueryBuilder::new(handle);
qb.tag(tag)
}
fn attr_name<'a, P>(&self, name: P) -> QueryBuilder<'a, AttrQuery<P, bool>, QueryWrapper<'a, (), ()>>
where
P: Pattern
{
let handle = self.get_handle();
let qb = QueryBuilder::new(handle);
qb.attr_name(name)
}
fn attr_value<'a, P>(&self, value: P) -> QueryBuilder<'a, AttrQuery<bool, P>, QueryWrapper<'a, (), ()>>
where
P: Pattern
{
let handle = self.get_handle();
let qb = QueryBuilder::new(handle);
qb.attr_value(value)
}
fn attr<'a, P, Q>(
&self,
name: P,
value: Q,
) -> QueryBuilder<'a, AttrQuery<P, Q>, QueryWrapper<'a, (), ()>>
where
P: Pattern,
Q: Pattern,
{
let handle = self.get_handle();
let qb = QueryBuilder::new(handle);
qb.attr(name, value)
}
fn class<'a, P: Pattern>(
&self,
value: P,
) -> QueryBuilder<'a, AttrQuery<&'static str, P>, QueryWrapper<'a, (), ()>> {
let handle = self.get_handle();
let qb = QueryBuilder::new(handle);
qb.class(value)
}
fn recursive<'a>(&self, recursive: bool) -> QueryBuilder<'a, (), ()> {
let handle = self.get_handle();
let qb = QueryBuilder::new(handle);
qb.recursive(recursive)
}
fn children(&self) -> NodeChildIter {
let handle = self.get_handle();
NodeChildIter::new(handle.clone())
}
fn parents(&self) -> NodeParentIter {
NodeParentIter::new(self.get_handle().clone())
}
}
pub struct NodeParentIter {
inner: Handle,
}
impl fmt::Debug for NodeParentIter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::node_ext::NodeExt;
f.debug_struct("NodeParentIter")
.field("inner", &format!("{}", self.inner.display()))
.finish()
}
}
impl NodeParentIter {
pub fn new(handle: Handle) -> NodeParentIter {
NodeParentIter { inner: handle }
}
}
impl Iterator for NodeParentIter {
type Item = Handle;
fn next(&mut self) -> Option<Self::Item> {
use crate::node_ext::NodeExt;
if let Some(ref parent) = self.inner.parent() {
self.inner = parent.clone();
Some(parent.clone())
} else {
None
}
}
}
pub struct NodeChildIter {
inner: Handle,
idx: usize,
}
impl NodeChildIter {
pub fn new(handle: Handle) -> NodeChildIter {
NodeChildIter {
inner: handle,
idx: 0,
}
}
fn len(&self) -> usize {
self.inner.children.borrow().len()
}
}
impl Iterator for NodeChildIter {
type Item = Handle;
fn next(&mut self) -> Option<Self::Item> {
let item = self.inner.children.borrow().get(self.idx).cloned();
self.idx += 1;
item
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.len()))
}
}
impl fmt::Debug for NodeChildIter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("NodeChildIter")
.field("handle", &"<handle>")
.field("idx", &self.idx)
.finish()
}
}
impl QueryBuilderExt for Handle {
fn get_handle(&self) -> Handle {
self.clone()
}
}
impl QueryBuilderExt for Soup {
fn get_handle(&self) -> Handle {
self.handle.document.clone()
}
}