use html5ever::tree_builder::QuirksMode;
use html5ever::QualName;
use std::cell::{Cell, RefCell};
use std::fmt;
use std::ops::Deref;
use std::rc::{Rc, Weak};
use crate::attributes::{Attribute, Attributes, ExpandedName};
use crate::cell_extras::*;
use crate::iter::NodeIterator;
#[derive(Debug, PartialEq, Clone)]
pub enum NodeData {
Element(ElementData),
Text(RefCell<String>),
Comment(RefCell<String>),
ProcessingInstruction(RefCell<(String, String)>),
Doctype(Doctype),
Document(DocumentData),
DocumentFragment,
}
#[derive(Debug, PartialEq, Clone)]
pub struct Doctype {
pub name: String,
pub public_id: String,
pub system_id: String,
}
#[derive(Debug, PartialEq, Clone)]
pub struct ElementData {
pub name: QualName,
pub attributes: RefCell<Attributes>,
pub template_contents: Option<NodeRef>,
}
#[derive(Debug, PartialEq, Clone)]
pub struct DocumentData {
#[doc(hidden)]
pub _quirks_mode: Cell<QuirksMode>,
}
impl DocumentData {
#[inline]
pub fn quirks_mode(&self) -> QuirksMode {
self._quirks_mode.get()
}
}
#[derive(Clone, Debug)]
pub struct NodeRef(pub Rc<Node>);
impl Deref for NodeRef {
type Target = Node;
#[inline]
fn deref(&self) -> &Node {
&*self.0
}
}
impl Eq for NodeRef {}
impl PartialEq for NodeRef {
#[inline]
fn eq(&self, other: &NodeRef) -> bool {
let a: *const Node = &*self.0;
let b: *const Node = &*other.0;
a == b
}
}
pub struct Node {
parent: Cell<Option<Weak<Node>>>,
previous_sibling: Cell<Option<Weak<Node>>>,
next_sibling: Cell<Option<Rc<Node>>>,
first_child: Cell<Option<Rc<Node>>>,
last_child: Cell<Option<Weak<Node>>>,
data: NodeData,
}
impl fmt::Debug for Node {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{:?} @ {:?}", self.data, self as *const Node)
}
}
impl Drop for Node {
fn drop(&mut self) {
let mut stack = Vec::new();
if let Some(rc) = self.first_child.take_if_unique_strong() {
non_recursive_drop_unique_rc(rc, &mut stack);
}
if let Some(rc) = self.next_sibling.take_if_unique_strong() {
non_recursive_drop_unique_rc(rc, &mut stack);
}
fn non_recursive_drop_unique_rc(mut rc: Rc<Node>, stack: &mut Vec<Rc<Node>>) {
loop {
if let Some(child) = rc.first_child.take_if_unique_strong() {
stack.push(rc);
rc = child;
continue;
}
if let Some(sibling) = rc.next_sibling.take_if_unique_strong() {
rc = sibling;
continue;
}
if let Some(parent) = stack.pop() {
rc = parent;
continue;
}
return;
}
}
}
}
impl NodeRef {
#[inline]
pub fn new(data: NodeData) -> NodeRef {
NodeRef(Rc::new(Node {
parent: Cell::new(None),
first_child: Cell::new(None),
last_child: Cell::new(None),
previous_sibling: Cell::new(None),
next_sibling: Cell::new(None),
data,
}))
}
#[inline]
pub fn new_element<I>(name: QualName, attributes: I) -> NodeRef
where
I: IntoIterator<Item = (ExpandedName, Attribute)>,
{
NodeRef::new(NodeData::Element(ElementData {
template_contents: if name.expanded() == expanded_name!(html "template") {
Some(NodeRef::new(NodeData::DocumentFragment))
} else {
None
},
name,
attributes: RefCell::new(Attributes {
map: attributes.into_iter().collect(),
}),
}))
}
#[inline]
pub fn new_text<T: Into<String>>(value: T) -> NodeRef {
NodeRef::new(NodeData::Text(RefCell::new(value.into())))
}
#[inline]
pub fn new_comment<T: Into<String>>(value: T) -> NodeRef {
NodeRef::new(NodeData::Comment(RefCell::new(value.into())))
}
#[inline]
pub fn new_processing_instruction<T1, T2>(target: T1, data: T2) -> NodeRef
where
T1: Into<String>,
T2: Into<String>,
{
NodeRef::new(NodeData::ProcessingInstruction(RefCell::new((
target.into(),
data.into(),
))))
}
#[inline]
pub fn new_doctype<T1, T2, T3>(name: T1, public_id: T2, system_id: T3) -> NodeRef
where
T1: Into<String>,
T2: Into<String>,
T3: Into<String>,
{
NodeRef::new(NodeData::Doctype(Doctype {
name: name.into(),
public_id: public_id.into(),
system_id: system_id.into(),
}))
}
#[inline]
pub fn new_document() -> NodeRef {
NodeRef::new(NodeData::Document(DocumentData {
_quirks_mode: Cell::new(QuirksMode::NoQuirks),
}))
}
pub fn text_contents(&self) -> String {
let mut s = String::new();
for text_node in self.inclusive_descendants().text_nodes() {
s.push_str(&text_node.borrow());
}
s
}
}
impl Node {
#[inline]
pub fn data(&self) -> &NodeData {
&self.data
}
#[inline]
pub fn as_element(&self) -> Option<&ElementData> {
match self.data {
NodeData::Element(ref value) => Some(value),
_ => None,
}
}
#[inline]
pub fn as_text(&self) -> Option<&RefCell<String>> {
match self.data {
NodeData::Text(ref value) => Some(value),
_ => None,
}
}
#[inline]
pub fn as_comment(&self) -> Option<&RefCell<String>> {
match self.data {
NodeData::Comment(ref value) => Some(value),
_ => None,
}
}
#[inline]
pub fn as_doctype(&self) -> Option<&Doctype> {
match self.data {
NodeData::Doctype(ref value) => Some(value),
_ => None,
}
}
#[inline]
pub fn as_document(&self) -> Option<&DocumentData> {
match self.data {
NodeData::Document(ref value) => Some(value),
_ => None,
}
}
#[inline]
pub fn parent(&self) -> Option<NodeRef> {
self.parent.upgrade().map(NodeRef)
}
#[inline]
pub fn first_child(&self) -> Option<NodeRef> {
self.first_child.clone_inner().map(NodeRef)
}
#[inline]
pub fn last_child(&self) -> Option<NodeRef> {
self.last_child.upgrade().map(NodeRef)
}
#[inline]
pub fn previous_sibling(&self) -> Option<NodeRef> {
self.previous_sibling.upgrade().map(NodeRef)
}
#[inline]
pub fn next_sibling(&self) -> Option<NodeRef> {
self.next_sibling.clone_inner().map(NodeRef)
}
pub fn detach(&self) {
let parent_weak = self.parent.take();
let previous_sibling_weak = self.previous_sibling.take();
let next_sibling_strong = self.next_sibling.take();
let previous_sibling_opt = previous_sibling_weak
.as_ref()
.and_then(|weak| weak.upgrade());
if let Some(next_sibling_ref) = next_sibling_strong.as_ref() {
next_sibling_ref
.previous_sibling
.replace(previous_sibling_weak);
} else if let Some(parent_ref) = parent_weak.as_ref() {
if let Some(parent_strong) = parent_ref.upgrade() {
parent_strong.last_child.replace(previous_sibling_weak);
}
}
if let Some(previous_sibling_strong) = previous_sibling_opt {
previous_sibling_strong
.next_sibling
.replace(next_sibling_strong);
} else if let Some(parent_ref) = parent_weak.as_ref() {
if let Some(parent_strong) = parent_ref.upgrade() {
parent_strong.first_child.replace(next_sibling_strong);
}
}
}
}
impl NodeRef {
pub fn append(&self, new_child: NodeRef) {
new_child.detach();
new_child.parent.replace(Some(Rc::downgrade(&self.0)));
if let Some(last_child_weak) = self.last_child.replace(Some(Rc::downgrade(&new_child.0))) {
if let Some(last_child) = last_child_weak.upgrade() {
new_child.previous_sibling.replace(Some(last_child_weak));
debug_assert!(last_child.next_sibling.is_none());
last_child.next_sibling.replace(Some(new_child.0));
return;
}
}
debug_assert!(self.first_child.is_none());
self.first_child.replace(Some(new_child.0));
}
pub fn prepend(&self, new_child: NodeRef) {
new_child.detach();
new_child.parent.replace(Some(Rc::downgrade(&self.0)));
if let Some(first_child) = self.first_child.take() {
debug_assert!(first_child.previous_sibling.is_none());
first_child
.previous_sibling
.replace(Some(Rc::downgrade(&new_child.0)));
new_child.next_sibling.replace(Some(first_child));
} else {
debug_assert!(self.first_child.is_none());
self.last_child.replace(Some(Rc::downgrade(&new_child.0)));
}
self.first_child.replace(Some(new_child.0));
}
pub fn insert_after(&self, new_sibling: NodeRef) {
new_sibling.detach();
new_sibling.parent.replace(self.parent.clone_inner());
new_sibling
.previous_sibling
.replace(Some(Rc::downgrade(&self.0)));
if let Some(next_sibling) = self.next_sibling.take() {
debug_assert!(next_sibling.previous_sibling().unwrap() == *self);
next_sibling
.previous_sibling
.replace(Some(Rc::downgrade(&new_sibling.0)));
new_sibling.next_sibling.replace(Some(next_sibling));
} else if let Some(parent) = self.parent() {
debug_assert!(parent.last_child().unwrap() == *self);
parent
.last_child
.replace(Some(Rc::downgrade(&new_sibling.0)));
}
self.next_sibling.replace(Some(new_sibling.0));
}
pub fn insert_before(&self, new_sibling: NodeRef) {
new_sibling.detach();
new_sibling.parent.replace(self.parent.clone_inner());
new_sibling.next_sibling.replace(Some(self.0.clone()));
if let Some(previous_sibling_weak) = self
.previous_sibling
.replace(Some(Rc::downgrade(&new_sibling.0)))
{
if let Some(previous_sibling) = previous_sibling_weak.upgrade() {
new_sibling
.previous_sibling
.replace(Some(previous_sibling_weak));
debug_assert!(previous_sibling.next_sibling().unwrap() == *self);
previous_sibling.next_sibling.replace(Some(new_sibling.0));
return;
}
}
if let Some(parent) = self.parent() {
debug_assert!(parent.first_child().unwrap() == *self);
parent.first_child.replace(Some(new_sibling.0));
}
}
}