use std::iter::FilterMap;
use std::cell::{Ref, RefMut};
use crate::{
tree,
Attribute,
AttributeId,
AttributeQName,
AttributeQNameRef,
Attributes,
AttributeValue,
ElementId,
Error,
NodeData,
NodeType,
PaintFallback,
QName,
QNameRef,
TagName,
TagNameRef,
};
impl<'a, N, V> From<(N, V)> for Attribute
where AttributeQNameRef<'a>: From<N>, AttributeValue: From<V>
{
fn from(v: (N, V)) -> Self {
Attribute::new(v.0, v.1)
}
}
impl<'a, N> From<(N, Node)> for Attribute
where AttributeQNameRef<'a>: From<N>, N: Clone
{
fn from(v: (N, Node)) -> Self {
let n = AttributeQNameRef::from(v.0.clone());
if n.has_id(AttributeId::Href) {
Attribute::new(v.0, AttributeValue::Link(v.1))
} else if n.has_id(AttributeId::Fill) || n.has_id(AttributeId::Stroke) {
Attribute::new(v.0, AttributeValue::Paint(v.1, None))
} else {
Attribute::new(v.0, AttributeValue::FuncLink(v.1))
}
}
}
impl<'a, N> From<(N, (Node, Option<PaintFallback>))> for Attribute
where AttributeQNameRef<'a>: From<N>, N: Clone
{
fn from(v: (N, (Node, Option<PaintFallback>))) -> Self {
Attribute::new(v.0, AttributeValue::Paint((v.1).0, (v.1).1))
}
}
pub type Node = tree::Node<NodeData>;
impl Node {
pub fn has_parent(&self) -> bool {
match self.parent() {
Some(node) => !node.is_root(),
None => false,
}
}
pub fn node_type(&self) -> NodeType {
self.borrow().node_type
}
pub fn is_root(&self) -> bool {
self.node_type() == NodeType::Root
}
pub fn is_element(&self) -> bool {
self.node_type() == NodeType::Element
}
pub fn is_comment(&self) -> bool {
self.node_type() == NodeType::Comment
}
pub fn is_text(&self) -> bool {
self.node_type() == NodeType::Text
}
pub fn is_detached(&self) -> bool {
self.borrow().storage_key.is_none()
}
pub fn text(&self) -> Ref<String> {
Ref::map(self.borrow(), |d| &d.text)
}
pub fn text_mut(&mut self) -> RefMut<String> {
RefMut::map(self.borrow_mut(), |d| &mut d.text)
}
pub fn set_text(&mut self, text: &str) {
debug_assert_ne!(self.node_type(), NodeType::Element);
self.borrow_mut().text = text.to_owned();
}
pub fn id(&self) -> Ref<String> {
Ref::map(self.borrow(), |d| &d.id)
}
pub fn has_id(&self) -> bool {
!self.id().is_empty()
}
pub fn set_id<S: Into<String>>(&mut self, id: S) {
debug_assert_eq!(self.node_type(), NodeType::Element);
self.borrow_mut().id = id.into().to_owned();
}
pub fn is_svg_element(&self) -> bool {
if !self.is_element() {
return false;
}
match self.borrow().tag_name {
QName::Id(_) => true,
QName::Name(_) => false,
}
}
pub fn tag_name(&self) -> Ref<TagName> {
Ref::map(self.borrow(), |d| &d.tag_name)
}
pub fn tag_id(&self) -> Option<ElementId> {
match self.borrow().tag_name {
QName::Id(id) => Some(id),
QName::Name(_) => None,
}
}
pub fn has_tag_name<'a, T>(&self, tag_name: T) -> bool
where TagNameRef<'a>: From<T>
{
self.borrow().tag_name.as_ref() == TagNameRef::from(tag_name)
}
pub fn set_tag_name<'a, T>(&mut self, tag_name: T)
where TagNameRef<'a>: From<T>
{
debug_assert_eq!(self.node_type(), NodeType::Element);
let tn = TagNameRef::from(tag_name);
if let QNameRef::Name(name) = tn {
if name.is_empty() {
panic!("supplied tag name is empty");
}
}
self.borrow_mut().tag_name = TagName::from(tn);
}
pub fn attributes(&self) -> Ref<Attributes> {
Ref::map(self.borrow(), |d| &d.attributes)
}
pub fn attributes_mut(&mut self) -> RefMut<Attributes> {
RefMut::map(self.borrow_mut(), |d| &mut d.attributes)
}
#[inline]
pub fn has_attribute<'a, N>(&self, name: N) -> bool
where AttributeQNameRef<'a>: From<N>
{
self.borrow().attributes.contains(name)
}
pub fn set_attribute<T>(&mut self, v: T)
where T: Into<Attribute>
{
self.set_attribute_checked(v).unwrap();
}
pub fn set_attribute_checked<T>(&mut self, v: T) -> Result<(), Error>
where T: Into<Attribute>
{
self.set_attribute_checked_impl(v.into())
}
fn set_attribute_checked_impl(&mut self, attr: Attribute) -> Result<(), Error> {
debug_assert!(self.node_type() == NodeType::Element);
match attr.value {
AttributeValue::Link(ref iri)
| AttributeValue::FuncLink(ref iri) => {
self.set_link_attribute(attr.name, iri.clone(), None)?;
return Ok(());
}
AttributeValue::Paint(ref iri, fallback) => {
self.set_link_attribute(attr.name, iri.clone(), fallback)?;
return Ok(());
}
_ => {}
}
self.set_simple_attribute(attr);
Ok(())
}
fn set_simple_attribute(&mut self, attr: Attribute) {
debug_assert!(!attr.is_link_container());
self.remove_attribute(attr.name.as_ref());
let mut attrs = self.attributes_mut();
attrs.insert(attr);
}
fn set_link_attribute(
&mut self,
name: AttributeQName,
mut node: Node,
fallback: Option<PaintFallback>,
) -> Result<(), Error> {
if node.id().is_empty() {
return Err(Error::ElementMustHaveAnId);
}
if *self.id() == *node.id() {
return Err(Error::ElementCrosslink);
}
if self.linked_nodes().iter().any(|n| *n == node) {
return Err(Error::ElementCrosslink);
}
self.remove_attribute(name.as_ref());
{
let a = if name.has_id(AttributeId::Href) {
Attribute::new(name.as_ref(), AttributeValue::Link(node.clone()))
} else if name.has_id(AttributeId::Fill) || name.has_id(AttributeId::Stroke) {
Attribute::new(name.as_ref(), AttributeValue::Paint(node.clone(), fallback))
} else {
Attribute::new(name.as_ref(), AttributeValue::FuncLink(node.clone()))
};
let mut attributes = self.attributes_mut();
attributes.insert(a);
}
node.borrow_mut().linked_nodes.push(self.clone());
Ok(())
}
pub fn set_attribute_if_none<'a, T>(&mut self, v: T)
where T: Into<Attribute>
{
let attr: Attribute = v.into();
if !self.has_attribute(attr.name.as_ref()) {
self.set_attribute(attr);
}
}
pub fn remove_attribute<'a, N>(&mut self, name: N)
where AttributeQNameRef<'a>: From<N>, N: Copy
{
if !self.has_attribute(name) {
return;
}
if let Some(value) = self.attributes().get_value(name) {
match *value {
AttributeValue::Link(ref node)
| AttributeValue::FuncLink(ref node)
| AttributeValue::Paint(ref node, _) => {
let mut node = node.clone();
let index = node.borrow().linked_nodes.iter().position(|n| n == self).unwrap();
node.borrow_mut().linked_nodes.remove(index);
}
_ => {}
}
}
self.attributes_mut().remove(name);
}
pub fn linked_nodes(&self) -> Ref<Vec<Node>> {
Ref::map(self.borrow(), |d| &d.linked_nodes)
}
pub fn linked_nodes_mut(&mut self) -> RefMut<Vec<Node>> {
RefMut::map(self.borrow_mut(), |d| &mut d.linked_nodes)
}
pub fn is_used(&self) -> bool {
!self.linked_nodes().is_empty()
}
pub fn uses_count(&self) -> usize {
self.linked_nodes().len()
}
}
pub trait FilterSvg: Iterator {
fn svg(self) -> FilterMap<Self, fn(Node) -> Option<(ElementId, Node)>>
where Self: Iterator<Item = Node> + Sized,
{
fn is_svg(node: Node) -> Option<(ElementId, Node)> {
if let QName::Id(id) = *node.tag_name() {
return Some((id, node.clone()));
}
None
}
self.filter_map(is_svg)
}
}
impl<'a, I: Iterator<Item = Node>> FilterSvg for I {}