use std::fmt;
use log::warn;
use slab::Slab;
use crate::parser::parse_svg;
use crate::writer;
use crate::{
AttributeQName,
Attributes,
AttributeValue,
ElementId,
FilterSvg,
FilterSvgAttrs,
Node,
NodeData,
NodeType,
ParserError,
QName,
QNameRef,
TagNameRef,
WriteOptions,
};
pub struct Document {
root: Node,
storage: Slab<Node>,
}
impl Document {
pub fn new() -> Document {
let mut storage = Slab::new();
let mut root = Node::new(NodeData {
storage_key: None,
node_type: NodeType::Root,
tag_name: QName::Name(String::new()),
id: String::new(),
attributes: Attributes::new(),
linked_nodes: Vec::new(),
text: String::new(),
});
let key = storage.insert(root.clone());
root.borrow_mut().storage_key = Some(key);
Document {
root,
storage,
}
}
pub fn from_str(text: &str) -> Result<Document, ParserError> {
parse_svg(text)
}
pub fn to_string_with_opt(&self, opt: &WriteOptions) -> String {
writer::write_dom(self, opt)
}
pub fn create_element<'a, T>(&mut self, tag_name: T) -> Node
where TagNameRef<'a>: From<T>, T: Copy
{
let tn = QNameRef::from(tag_name);
if let QNameRef::Name(name) = tn {
if name.is_empty() {
panic!("supplied tag name is empty");
}
}
let mut node = Node::new(NodeData {
storage_key: None,
node_type: NodeType::Element,
tag_name: QNameRef::from(tag_name).into(),
id: String::new(),
attributes: Attributes::new(),
linked_nodes: Vec::new(),
text: String::new(),
});
let key = self.storage.insert(node.clone());
node.borrow_mut().storage_key = Some(key);
node
}
pub fn create_node<S: Into<String>>(&mut self, node_type: NodeType, text: S) -> Node {
assert!(node_type != NodeType::Element && node_type != NodeType::Root);
let mut node = Node::new(NodeData {
storage_key: None,
node_type,
tag_name: QName::Name(String::new()),
id: String::new(),
attributes: Attributes::new(),
linked_nodes: Vec::new(),
text: text.into(),
});
let key = self.storage.insert(node.clone());
node.borrow_mut().storage_key = Some(key);
node
}
pub fn root(&self) -> Node {
self.root.clone()
}
pub fn svg_element(&self) -> Option<Node> {
for (id, n) in self.root().children().svg() {
if id == ElementId::Svg {
return Some(n.clone());
}
}
None
}
pub fn remove_node(&mut self, node: Node) {
let mut ids = Vec::with_capacity(16);
self._remove(node.clone(), &mut ids);
}
fn _remove(&mut self, mut node: Node, ids: &mut Vec<AttributeQName>) {
ids.clear();
for (_, attr) in node.attributes().iter().svg() {
match attr.value {
AttributeValue::Link(_)
| AttributeValue::FuncLink(_)
| AttributeValue::Paint(_, _) => {
ids.push(attr.name.clone())
}
_ => {}
}
}
for name in ids.iter() {
node.remove_attribute(name.as_ref());
}
let linked_nodes = node.linked_nodes().clone();
for mut linked in linked_nodes {
ids.clear();
for (_, attr) in linked.attributes().iter().svg() {
match attr.value {
AttributeValue::Link(ref link)
| AttributeValue::FuncLink(ref link)
| AttributeValue::Paint(ref link, _) => {
if *link == node {
ids.push(attr.name.clone())
}
}
_ => {}
}
}
for name in ids.iter() {
linked.remove_attribute(name.as_ref());
}
}
for child in node.children() {
self._remove(child, ids);
}
node.detach();
let key = node.borrow_mut().storage_key.take();
if let Some(key) = key {
self.storage.remove(key);
} else {
warn!("Node was already removed.")
}
}
pub fn drain<P>(&mut self, root: Node, f: P) -> usize
where P: Fn(&Node) -> bool
{
let mut count = 0;
self._drain(root, &f, &mut count);
count
}
fn _drain<P>(&mut self, parent: Node, f: &P, count: &mut usize)
where P: Fn(&Node) -> bool
{
let mut node = parent.first_child();
while let Some(n) = node {
if f(&n) {
node = n.next_sibling();
self.remove_node(n);
*count += 1;
} else {
if n.has_children() {
self._drain(n.clone(), f, count);
}
node = n.next_sibling();
}
}
}
pub fn copy_node(&mut self, node: Node) -> Node {
match node.node_type() {
NodeType::Element => {
let mut elem = self.create_element(node.tag_name().as_ref());
for attr in node.attributes().iter() {
elem.set_attribute(attr.clone());
}
elem
}
_ => {
self.create_node(node.node_type(), node.text().clone())
}
}
}
pub fn copy_node_deep(&mut self, node: Node) -> Node {
let mut root = self.copy_node(node.clone());
self._make_deep_copy(&mut root, &node);
root
}
fn _make_deep_copy(&mut self, parent: &mut Node, node: &Node) {
for child in node.children() {
let mut new_node = self.copy_node(child.clone());
parent.append(new_node.clone());
if child.has_children() {
self._make_deep_copy(&mut new_node, &child);
}
}
}
}
impl Drop for Document {
fn drop(&mut self) {
for (_, node) in self.storage.iter_mut() {
node.attributes_mut().clear();
node.linked_nodes_mut().clear();
node.detach();
}
}
}
impl fmt::Display for Document {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let data = writer::write_dom(self, &WriteOptions::default());
write!(f, "{}", data)
}
}