use std::fmt;
use std::ops::Deref;
use std::collections::{HashSet, HashMap};
use std::collections::{hash_set, hash_map};
use string_cache::{QualName, Atom};
use tendril::StrTendril;
#[derive(Clone, PartialEq, Eq)]
pub enum Node {
Document,
Fragment,
Doctype(Doctype),
Comment(Comment),
Text(Text),
Element(Element),
}
impl Node {
pub fn is_document(&self) -> bool {
match *self { Node::Document => true, _ => false }
}
pub fn is_fragment(&self) -> bool {
match *self { Node::Fragment => true, _ => false }
}
pub fn is_doctype(&self) -> bool {
match *self { Node::Doctype(_) => true, _ => false }
}
pub fn is_comment(&self) -> bool {
match *self { Node::Comment(_) => true, _ => false }
}
pub fn is_text(&self) -> bool {
match *self { Node::Text(_) => true, _ => false }
}
pub fn is_element(&self) -> bool {
match *self { Node::Element(_) => true, _ => false }
}
pub fn as_doctype(&self) -> Option<&Doctype> {
match *self { Node::Doctype(ref d) => Some(d), _ => None }
}
pub fn as_comment(&self) -> Option<&Comment> {
match *self { Node::Comment(ref c) => Some(c), _ => None }
}
pub fn as_text(&self) -> Option<&Text> {
match *self { Node::Text(ref t) => Some(t), _ => None }
}
pub fn as_element(&self) -> Option<&Element> {
match *self { Node::Element(ref e) => Some(e), _ => None }
}
}
impl fmt::Debug for Node {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Node::Document => write!(f, "Document"),
Node::Fragment => write!(f, "Fragment"),
Node::Doctype(ref d) => write!(f, "Doctype({:?})", d),
Node::Comment(ref c) => write!(f, "Comment({:?})", c),
Node::Text(ref t) => write!(f, "Text({:?})", t),
Node::Element(ref e) => write!(f, "Element({:?})", e),
}
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct Doctype {
pub name: StrTendril,
pub public_id: StrTendril,
pub system_id: StrTendril,
}
impl Doctype {
pub fn name(&self) -> &str {
self.name.deref()
}
pub fn public_id(&self) -> &str {
self.public_id.deref()
}
pub fn system_id(&self) -> &str {
self.system_id.deref()
}
}
impl fmt::Debug for Doctype {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
f,
"<!DOCTYPE {} PUBLIC {:?} {:?}>",
self.name(),
self.public_id(),
self.system_id()
)
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct Comment {
pub comment: StrTendril,
}
impl Deref for Comment {
type Target = str;
fn deref(&self) -> &str {
self.comment.deref()
}
}
impl fmt::Debug for Comment {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "<!-- {:?} -->", self.deref())
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct Text {
pub text: StrTendril,
}
impl Deref for Text {
type Target = str;
fn deref(&self) -> &str {
self.text.deref()
}
}
impl fmt::Debug for Text {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{:?}", self.deref())
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct Element {
pub name: QualName,
pub id: Option<Atom>,
pub classes: HashSet<Atom>,
pub attrs: HashMap<QualName, StrTendril>,
}
impl Element {
#[doc(hidden)]
pub fn new(name: QualName, attrs: HashMap<QualName, StrTendril>) -> Self {
let id = attrs.get(&qualname!("", "id"))
.map(Deref::deref)
.map(Atom::from);
let classes = attrs.get(&qualname!("", "class"))
.map(Deref::deref)
.into_iter()
.flat_map(str::split_whitespace)
.map(Atom::from)
.collect();
Element {
name: name,
id: id,
classes: classes,
attrs: attrs,
}
}
pub fn name(&self) -> &str {
self.name.local.deref()
}
pub fn id(&self) -> Option<&str> {
self.id.as_ref().map(Deref::deref)
}
pub fn has_class(&self, class: &str) -> bool {
self.classes.contains(&Atom::from(class))
}
pub fn classes(&self) -> Classes {
Classes { inner: self.classes.iter() }
}
pub fn attr(&self, attr: &str) -> Option<&str> {
let qualname = QualName::new(ns!(), Atom::from(attr));
self.attrs.get(&qualname).map(Deref::deref)
}
pub fn attrs(&self) -> Attrs {
Attrs { inner: self.attrs.iter() }
}
}
#[allow(missing_debug_implementations)]
#[derive(Clone)]
pub struct Classes<'a> {
inner: hash_set::Iter<'a, Atom>,
}
impl<'a> Iterator for Classes<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<&'a str> {
self.inner.next().map(Deref::deref)
}
}
#[allow(missing_debug_implementations)]
#[derive(Clone)]
pub struct Attrs<'a> {
inner: hash_map::Iter<'a, QualName, StrTendril>,
}
impl<'a> Iterator for Attrs<'a> {
type Item = (&'a str, &'a str);
fn next(&mut self) -> Option<(&'a str, &'a str)> {
self.inner.next().map(|(k, v)| (k.local.deref(), v.deref()))
}
}
impl fmt::Debug for Element {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
try!(write!(f, "<{}", self.name()));
for (key, value) in self.attrs() {
try!(write!(f, " {}={:?}", key, value));
}
write!(f, ">")
}
}