use std::sync::Arc;
use tree::Tree;
use node::{Node, Content};
use errors::{Result, ErrorKind};
use containers::Container;
pub fn cow_node(node: &Arc<Node>) -> Arc<Node> {
let mut new_node = node.clone();
Arc::make_mut(&mut new_node).version += 1;
new_node
}
#[derive(Eq, PartialEq)]
pub enum IterContent<'a> {
Directory(Vec<&'a str>),
Container(&'a Container)
}
#[derive(Eq, PartialEq)]
pub struct IterNode<'a> {
pub path: &'a str,
pub version: u64,
pub content: IterContent<'a>
}
pub struct Iter<'a> {
stack: Vec<&'a Arc<Node>>
}
impl<'a> Iter<'a> {
pub fn new(root: &'a Arc<Node>) -> Iter<'a> {
Iter { stack: vec![root] }
}
}
impl<'a> Iterator for Iter<'a> {
type Item = IterNode<'a>;
fn next(&mut self) -> Option<IterNode<'a>> {
if self.stack.is_empty() {
return None;
}
let node = self.stack.pop().unwrap();
let content = match node.content {
Content::Directory(ref edges) => {
self.stack.extend(edges.iter().rev().map(|edge| &edge.node));
IterContent::Directory(edges.iter().map(|edge| &edge.label as &str).collect())
}
Content::Container(ref container) => IterContent::Container(container),
};
Some(IterNode {
path: &node.path,
version: node.version,
content: content
})
}
}
pub struct CowPathIter<'a> {
tree: Tree,
paths: Vec<&'a str>,
stack: Vec<*mut Node>
}
impl<'a> CowPathIter<'a> {
pub fn new(root: &'a Arc<Node>, mut paths: Vec<&'a str>, max_depth: u32) -> CowPathIter<'a> {
paths.sort();
paths.dedup();
paths.reverse();
let mut stack = Vec::with_capacity(max_depth as usize);
let root = cow_node(root);
let ptr: *mut Node = &*root as *const Node as *mut Node;
stack.push(ptr);
CowPathIter {
tree: Tree {
root: root,
depth: max_depth
},
paths: paths,
stack: stack
}
}
fn walk(&mut self) -> Result<&'a mut Node> {
let path = self.paths.pop().unwrap();
loop {
unsafe {
let mut node = match self.stack.last() {
Some(node) => *node,
None => return Err(ErrorKind::DoesNotExist(path.to_string()).into()),
};
if path.starts_with(&(*node).path) {
let num_labels = (*node).path.split('/').skip_while(|&s| s == "").count();
let split = path.split('/').skip_while(|&s| s == "").skip(num_labels);
for label in split {
if label == "" {
continue;
}
node = cow_get_child(node, label)?;
let ptr: *mut Node = &mut (*node);
self.stack.push(ptr);
}
return Ok(&mut *node);
}
self.stack.pop();
}
}
}
pub fn get_tree(&self) -> Tree {
self.tree.clone()
}
}
impl<'a> Iterator for CowPathIter<'a> {
type Item = Result<&'a mut Node>;
fn next(&mut self) -> Option<Result<&'a mut Node>> {
if self.paths.is_empty() {
return None;
}
Some(self.walk())
}
}
pub struct PathIter<'a> {
paths: Vec<&'a str>,
stack: Vec<&'a Node>
}
impl<'a> PathIter<'a> {
pub fn new(root: &'a Arc<Node>, mut paths: Vec<&'a str>, max_depth: u32) -> PathIter<'a> {
paths.sort();
paths.dedup();
paths.reverse();
let mut stack = Vec::with_capacity(max_depth as usize);
let node_ref: &Node = &*root;
stack.push(node_ref);
PathIter {
paths: paths,
stack: stack
}
}
fn walk(&mut self) -> Result<&'a Node> {
let path = self.paths.pop().unwrap();
loop {
let mut node = match self.stack.last() {
Some(node) => *node,
None => return Err(ErrorKind::DoesNotExist(path.to_string()).into()),
};
if path.starts_with(&node.path) {
let num_labels = node.path.split('/').skip_while(|&s| s == "").count();
let split = path.split('/').skip_while(|&s| s == "").skip(num_labels);
let mut depth_from_current_node = 0;
for label in split {
depth_from_current_node += 1;
if label == "" {
continue;
}
node = get_child(node, label)?;
self.stack.push(node);
}
if depth_from_current_node > 0 {
return Ok(self.stack.last().unwrap());
}
}
self.stack.pop();
}
}
}
impl<'a> Iterator for PathIter<'a> {
type Item = Result<&'a Node>;
fn next(&mut self) -> Option<Result<&'a Node>> {
if self.paths.is_empty() {
return None;
}
Some(self.walk())
}
}
unsafe fn cow_get_child(node: *mut Node, label: &str) -> Result<*mut Node> {
if let Content::Directory(ref mut edges) = (*node).content {
match edges.binary_search_by_key(&label, |e| &e.label) {
Ok(index) => {
let mut edge = edges.get_unchecked_mut(index);
edge.node = cow_node(&edge.node);
let ptr: *mut Node = &*edge.node as *const Node as *mut Node;
return Ok(ptr);
}
Err(_) => {
let mut path = (*node).path.clone();
if &path != "/" {
path.push_str("/");
}
path.push_str(label);
return Err(ErrorKind::DoesNotExist(path).into());
}
}
}
Err(ErrorKind::InvalidPathContent((*node).path.clone()).into())
}
fn get_child<'a>(node: &'a Node, label: &'a str) -> Result<&'a Node> {
if let Content::Directory(ref edges) = node.content {
match edges.binary_search_by_key(&label, |e| &e.label) {
Ok(index) => unsafe {
return Ok(&*edges.get_unchecked(index).node);
},
Err(_) => {
let mut path = node.path.clone();
if &path != "/" {
path.push_str("/");
}
path.push_str(label);
return Err(ErrorKind::DoesNotExist(path).into());
}
}
}
Err(ErrorKind::InvalidPathContent(node.path.clone()).into())
}
#[cfg(test)]
mod tests {
use super::*;
use tree::Tree;
use node::*;
use containers::*;
use arbitrary::Path;
quickcheck! {
fn prop_walk_existing_paths(node_specs: Vec<(Path, NodeType)>) -> bool {
let (tree, node_specs) =
node_specs.iter().fold((Tree::new(),
Vec::new()),
|(tree, mut specs), &(ref path, node_type)|
{
match tree.create(&path.clone().0, node_type) {
Ok(new_tree) => {
specs.push((path.clone(), node_type));
(new_tree, specs)
},
Err(_) => (tree, specs)
}
});
if node_specs.len() as u64 != tree.root.version {
return false;
}
if node_specs.iter().any(|&(ref path, ty)| tree.find(&path.0, ty).is_err()) {
return false;
}
let paths = node_specs.iter().map(|&(ref path, _)| &path.0 as &str).collect();
tree.path_iter(paths).count() == node_specs.len()
}
}
#[test]
fn create_nodes_iter_check() {
let tree = Tree::new();
let tree = tree.create("/somenode", NodeType::Directory).unwrap();
let tree = tree.create("/somenode/somechildnode", NodeType::Set)
.unwrap();
let tree = tree.create("/somedir1/somedir2/leaf", NodeType::Queue)
.unwrap();
let expected = [("/", Some(2), 3),
("/somedir1", Some(1), 0),
("/somedir1/somedir2", Some(1), 0),
("/somedir1/somedir2/leaf", None, 0),
("/somenode", Some(1), 1),
("/somenode/somechildnode", None, 0)];
assert_eq!(tree.iter().count(), expected.len());
for (i, node) in tree.iter().enumerate() {
let (path, num_edges, version) = expected[i];
assert_eq!(node.path, path);
assert_eq!(node.version, version);
if let Some(num_edges) = num_edges {
if let IterContent::Directory(ref labels) =
node.content {
assert_eq!(labels.len(), num_edges);
} else {
assert!(false);
}
}
}
}
#[test]
fn path_iter() {
let tree = Tree::new();
let tree = tree.create("/somenode", NodeType::Directory).unwrap();
let tree = tree.create("/somenode/somechildnode", NodeType::Set)
.unwrap();
let tree = tree.create("/somedir1/somedir2/leaf", NodeType::Queue)
.unwrap();
let mut paths = vec!["/somenode/somechildnode",
"/somedir1/somedir2",
"/somedir1/somedir2/leaf",
"/somenode/"];
let iter = PathIter::new(&tree.root, paths.clone(), tree.depth);
let collected: Vec<&str> = iter.map(|node| &node.unwrap().path as &str).collect();
paths.sort();
let paths: Vec<&str> = paths.iter().map(|p| p.trim_right_matches('/')).collect();
assert_eq!(paths, collected);
}
#[test]
fn bad_path_iter() {
let tree = Tree::new();
let tree = tree.create("/somenode", NodeType::Directory).unwrap();
let tree = tree.create("/somenode/somechildnode", NodeType::Set)
.unwrap();
let tree = tree.create("/somedir1/somedir2/leaf", NodeType::Queue)
.unwrap();
let paths = vec!["/somenode/somechildnode", "/zzz"];
let mut iter = PathIter::new(&tree.root, paths, tree.depth);
assert_matches!(iter.next(), Some(Ok(_)));
assert_matches!(iter.next(), Some(Err(_)));
assert_matches!(iter.next(), None);
}
#[test]
fn cow_path_iter() {
let tree = Tree::new();
let tree = tree.create("/somenode", NodeType::Directory).unwrap();
let tree = tree.create("/somenode/somechildnode", NodeType::Blob)
.unwrap();
let tree = tree.create("/somedir1/somedir2/leaf", NodeType::Blob)
.unwrap();
assert_eq!(3, tree.root.version);
let paths = vec!["/somenode/somechildnode", "/somedir1/somedir2/leaf"];
let mut iter = CowPathIter::new(&tree.root, paths.clone(), tree.depth);
for node in iter.by_ref() {
let blob = "hello".to_string().into_bytes();
node.unwrap().content = Content::Container(Container::Blob(blob));
}
let cow_tree = iter.get_tree();
assert_eq!(3, tree.root.version);
assert_eq!(4, cow_tree.root.version);
let iter = PathIter::new(&tree.root, paths.clone(), tree.depth);
for node in iter {
let node = node.unwrap();
let blob = node.content.get_blob().unwrap();
assert_eq!(blob.len(), 0);
assert_eq!(node.version, 0);
}
let iter = PathIter::new(&cow_tree.root, paths.clone(), tree.depth);
for node in iter {
let node = node.unwrap();
let blob = node.content.get_blob().unwrap();
assert_eq!(&blob[..], "hello".as_bytes());
assert_eq!(node.version, 1);
}
}
}