use std::fmt;
use std::str;
use std::fmt::{Result};
pub use self::NodeContents::{Data, Children};
static NO_NAME : &'static str = "<none>";
pub struct PreOrderNodes<'a, 'b:'a> {
queue: Vec<&'a Node<'b>>
}
impl<'a, 'b:'a> Iterator for PreOrderNodes<'a, 'b> {
type Item = &'a Node<'b>;
fn next( &mut self ) -> Option<&'a Node<'b>> {
match self.queue.pop() {
Some( node ) => {
match node.contents {
Children( ref x ) => {
for child in x.iter().rev() {
self.queue.push( child )
}
}
_ => ()
};
Some( node )
}
_ => None
}
}
}
#[derive(Debug, PartialEq)]
pub enum NodeContents<'a> {
Data( &'a [u8] ),
Children( Vec<Node<'a>> )
}
#[derive(PartialEq)]
pub struct Node<'a> {
pub name: &'static str,
pub start: usize,
pub end: usize,
pub contents: NodeContents<'a>
}
fn indent( formatter: &mut fmt::Formatter, indent_spaces: u32 )
-> fmt::Result {
for _ in 0 .. indent_spaces {
try!( write!( formatter, " " ) )
}
Ok(())
}
impl<'a> Node<'a> {
fn format( &self, formatter: &mut fmt::Formatter, indent_spaces: u32 )
-> fmt::Result {
try!( indent( formatter, indent_spaces ) );
try!( write!( formatter,
"{0:?} [{1:?}, {2:?}>",
self.displayName(), self.start, self.end ) );
match self.contents {
Data( data ) => {
match str::from_utf8( data ) {
Ok( string ) => {
try!( writeln!( formatter,
": \"{0:?}\"",
string ) );
}
_ => {
try!( writeln!( formatter,
": \"{0:?}\"",
data ) );
}
}
}
Children( ref children ) => {
try!( writeln!( formatter, "" ) );
for child in children.iter() {
try!( child.format( formatter, indent_spaces + 1) )
}
}
};
Ok(())
}
pub fn displayName( &self ) -> &'static str {
if !self.name.is_empty() {
self.name
} else {
NO_NAME
}
}
pub fn withoutName( start: usize, end: usize, contents: NodeContents<'a> )
-> Node<'a> {
Node { name: "", start: start, end: end, contents: contents }
}
pub fn withChildren( name: &'static str, mut children: Vec<Node<'a>> )
-> Node<'a> {
if children.len() == 1 && children[ 0 ].name.is_empty() {
match children.pop() {
Some( mut child ) => {
child.name = name;
return child;
}
_ => ()
}
}
let start = if children.len() != 0 {
children[ 0 ].start
} else {
0
};
let end = children.last().map_or( 0, |node| node.end );
Node { name: name,
start: start,
end: end,
contents: Children( children ) }
}
#[allow(dead_code)]
pub fn preOrder<'b>( &'b self ) -> PreOrderNodes<'b, 'a> {
PreOrderNodes { queue: vec!( self ) }
}
#[allow(dead_code)]
pub fn matchedData( &self ) -> Vec<u8> {
match self.contents {
Data( x ) => x.to_vec(),
Children( ref children ) => {
let mut out : Vec<u8> = vec!();
for child in children.iter() {
out.extend( child.matchedData() );
}
out
}
}
}
}
impl<'a> fmt::Debug for Node<'a> {
fn fmt( &self, formatter: &mut fmt::Formatter ) -> fmt::Result {
self.format( formatter, 0 )
}
}
#[cfg(test)]
mod tests {
use super::{Node, Data};
fn nameOnly( name: &'static str ) -> Node {
Node { name: name, start: 0, end: 0, contents: Data( b"" ) }
}
fn contentsOnly( contents: &'static [u8] ) -> Node {
Node { name: "", start: 0, end: 0, contents: Data( contents ) }
}
fn testTree() -> Node<'static> {
Node::withChildren( "a", vec!(
Node::withChildren( "b", vec!( nameOnly( "e" ), nameOnly( "f" ) ) ),
Node::withChildren( "c", vec!( nameOnly( "g" ) ) ),
nameOnly( "d" ) ) )
}
fn testTreeWithContents() -> Node<'static> {
Node::withChildren( "a", vec!(
Node::withChildren(
"b", vec!( contentsOnly( b"e" ), contentsOnly( b"f" ) ) ),
Node::withChildren( "c", vec!( contentsOnly( b"g" ) ) ),
contentsOnly( b"d" ) ) )
}
#[test]
fn preOrder_FullIteration() {
let root = testTree();
let names =
root.preOrder().map( |x| x.name ).collect::<Vec<_>>();
assert_eq!( names, vec!( "a", "b", "e", "f", "c", "g", "d" ) )
}
#[test]
fn matchedData_FullTree() {
let root = testTreeWithContents();
assert_eq!( b"efgd", &root.matchedData()[..] )
}
}