use std::cell::RefCell;
use std::default::Default;
use std::borrow::Cow;
use std::ops::{Deref, DerefMut};
use std::rc::{Rc, Weak};
use tendril::StrTendril;
pub use self::NodeEnum::{Document, Doctype, Text, Comment, Element, PI};
use super::tokenizer::{Attribute, QName};
use super::tree_builder::{TreeSink, NodeOrText};
use super::ParseResult;
#[derive(Debug)]
pub enum NodeEnum {
Document,
Doctype(StrTendril, StrTendril, StrTendril),
Text(StrTendril),
Comment(StrTendril),
Element(QName, Vec<Attribute>),
PI(StrTendril, StrTendril),
}
pub struct Node {
pub node: NodeEnum,
pub parent: Option<WeakHandle>,
pub children: Vec<Handle>,
}
impl Node {
fn new(node: NodeEnum) -> Node {
Node {
node: node,
parent: None,
children: vec!(),
}
}
}
#[derive(Clone)]
pub struct Handle(Rc<RefCell<Node>>);
impl Deref for Handle {
type Target = Rc<RefCell<Node>>;
fn deref(&self) -> &Rc<RefCell<Node>> { &self.0 }
}
pub type WeakHandle = Weak<RefCell<Node>>;
fn new_node(node: NodeEnum) -> Handle {
Handle(Rc::new(RefCell::new(Node::new(node))))
}
fn append(new_parent: &Handle, child: Handle) {
new_parent.borrow_mut().children.push(child.clone());
let parent = &mut child.borrow_mut().parent;
assert!(parent.is_none());
*parent = Some(Rc::downgrade(new_parent));
}
fn append_to_existing_text(prev: &Handle, text: &str) -> bool {
match prev.borrow_mut().deref_mut().node {
Text(ref mut existing) => {
existing.push_slice(text);
true
}
_ => false,
}
}
pub struct RcDom {
pub document: Handle,
pub errors: Vec<Cow<'static, str>>,
}
impl TreeSink for RcDom {
type Handle = Handle;
fn parse_error(&mut self, msg: Cow<'static, str>) {
self.errors.push(msg);
}
fn get_document(&mut self) -> Handle {
self.document.clone()
}
fn elem_name(&self, target: &Handle) -> QName {
return match target.borrow().node {
Element(ref name, _) => name.clone(),
_ => panic!("not an element!"),
};
}
fn create_element(&mut self, name: QName, attrs: Vec<Attribute>) -> Handle {
new_node(Element(name, attrs))
}
fn create_comment(&mut self, text: StrTendril) -> Handle {
new_node(Comment(text))
}
fn create_pi(&mut self, target: StrTendril, data: StrTendril) -> Handle {
new_node(PI(target, data))
}
fn append(&mut self, parent: Handle, child: NodeOrText<Handle>) {
match child {
NodeOrText::AppendText(ref text) => match parent.borrow().children.last() {
Some(h) => if append_to_existing_text(h, &text) { return; },
_ => (),
},
_ => (),
}
append(&parent, match child {
NodeOrText::AppendText(text) => new_node(Text(text)),
NodeOrText::AppendNode(node) => node
});
}
fn append_doctype_to_document(&mut self,
name: StrTendril,
public_id: StrTendril,
system_id: StrTendril) {
append(&self.document, new_node(Doctype(name, public_id, system_id)));
}
}
impl Default for RcDom {
fn default() -> RcDom {
RcDom {
document: new_node(Document),
errors: vec!(),
}
}
}
impl ParseResult for RcDom {
type Sink = RcDom;
fn get_result(sink: RcDom) -> RcDom {
sink
}
}