blob: 905ee215b07c3f56faaeb2ce8bf12403cec11c10 [file] [log] [blame] [edit]
use super::element::Element;
use serde::Serialize;
#[derive(Debug, Clone, Serialize, PartialEq)]
#[serde(untagged)]
pub enum Node {
Text(String),
Element(Element),
Comment(String),
}
impl Node {
pub fn text(&self) -> Option<&str> {
match self {
Node::Text(t) => Some(t.as_str()),
_ => None,
}
}
pub fn element(&self) -> Option<&Element> {
match self {
Node::Element(e) => Some(e),
_ => None,
}
}
pub fn comment(&self) -> Option<&str> {
match self {
Node::Comment(t) => Some(t.as_str()),
_ => None,
}
}
}
impl<'a> IntoIterator for &'a Node {
type Item = &'a Node;
type IntoIter = NodeIntoIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
NodeIntoIterator {
node: self,
index: vec![],
}
}
}
pub struct NodeIntoIterator<'a> {
node: &'a Node,
// We add/remove to this vec each time we go up/down a node three
index: Vec<(usize, &'a Node)>,
}
impl<'a> Iterator for NodeIntoIterator<'a> {
type Item = &'a Node;
fn next(&mut self) -> Option<Self::Item> {
// Get first child
let child = match self.node {
Node::Element(ref e) => e.children.get(0),
_ => None,
};
let result = match child {
// If element has child, return child
Some(child) => {
self.index.push((0, self.node));
self.node = child;
Some(child)
}
// If element doesn't have a child, but is a child of another node
None if self.index.len() > 0 => {
let mut has_finished = false;
let mut next_node = None;
while !has_finished {
// Try to get the next sibling of the parent node
if let Some((sibling_index, parent)) = self.index.pop() {
let next_sibling = sibling_index + 1;
let sibling = if let Node::Element(ref e) = parent {
e.children.get(next_sibling)
} else {
None
};
if sibling.is_some() {
has_finished = true;
self.index.push((next_sibling, parent));
next_node = sibling;
} else {
continue;
}
// Break of there are no more parents
} else {
has_finished = true;
}
}
if let Some(next_node) = next_node {
self.node = next_node;
}
next_node
}
_ => None,
};
result
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn node_utillity_functions() {
let node = Node::Text("test".to_string());
assert_eq!(node.text(), Some("test"));
assert_eq!(node.element(), None);
assert_eq!(node.comment(), None);
let node = Node::Element(Element::default());
assert_eq!(node.text(), None);
assert_eq!(node.element(), Some(&Element::default()));
assert_eq!(node.comment(), None);
let node = Node::Comment("test".to_string());
assert_eq!(node.text(), None);
assert_eq!(node.element(), None);
assert_eq!(node.comment(), Some("test"));
}
}