use super::*;
#[inline]
pub fn set(root: &mut IVisit, path: &str, val: &str) -> BoxResult<bool> {
let mut result = Ok(false);
find(root, path, |node| {
if let NodeMut::Prop(prop) = node.as_node_mut() {
result = prop.set(val).map(|_| true);
}
});
result
}
#[inline]
pub fn get(root: &mut IVisit, path: &str) -> Option<String> {
let mut result = None;
find(root, path, |node| {
if let NodeMut::Prop(prop) = node.as_node_mut() {
result = Some(prop.get());
}
});
result
}
pub fn reset(root: &mut IVisit, path: &str) -> bool {
find(root, path, |node| {
match node.as_node_mut() {
NodeMut::Prop(prop) => prop.reset(),
NodeMut::List(list) => reset_all(list.as_visit_mut()),
NodeMut::Action(_) => (),
}
})
}
pub fn reset_all(root: &mut IVisit) {
root.visit_mut(&mut |node| {
match node.as_node_mut() {
NodeMut::Prop(prop) => prop.reset(),
NodeMut::List(list) => reset_all(list.as_visit_mut()),
NodeMut::Action(_) => (),
}
});
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum ComparePath<'a> {
False,
True,
Part(&'a str),
}
impl<'a> ComparePath<'a> {
fn cmp(path: &'a str, name: &str) -> ComparePath<'a> {
match path.as_bytes().get(name.len()) {
Some(&b'.') => {
if &path.as_bytes()[..name.len()] == name.as_bytes() {
ComparePath::Part(&path[name.len() + 1..])
}
else {
ComparePath::False
}
},
Some(_) => ComparePath::False,
None => if path == name { ComparePath::True } else { ComparePath::False },
}
}
}
#[test]
fn test_compare_id() {
assert_eq!(ComparePath::cmp("foo", "foo"), ComparePath::True);
assert_eq!(ComparePath::cmp("foo.bar", "foo"), ComparePath::Part("bar"));
assert_eq!(ComparePath::cmp("foo.bar", "foo.bar"), ComparePath::True);
assert_eq!(ComparePath::cmp("foo.bar.baz", "foo.bar"), ComparePath::Part("baz"));
assert_eq!(ComparePath::cmp("fooz", "foo"), ComparePath::False);
assert_eq!(ComparePath::cmp("foo.bar.baz", "bar.baz"), ComparePath::False);
assert_eq!(ComparePath::cmp("foo", "foo.bar"), ComparePath::False);
assert_eq!(ComparePath::cmp("foo.", "foo"), ComparePath::Part(""));
assert_eq!(ComparePath::cmp("foo.", "foo."), ComparePath::True);
assert_eq!(ComparePath::cmp("foo", "foo."), ComparePath::False);
assert_eq!(ComparePath::cmp("", ""), ComparePath::True);
assert_eq!(ComparePath::cmp(".", ""), ComparePath::Part(""));
assert_eq!(ComparePath::cmp(".", "."), ComparePath::True);
assert_eq!(ComparePath::cmp("", "."), ComparePath::False);
assert_eq!(ComparePath::cmp(".foo", "foo"), ComparePath::False);
assert_eq!(ComparePath::cmp(".foo", ".foo"), ComparePath::True);
assert_eq!(ComparePath::cmp("foo", ".foo"), ComparePath::False);
}
#[inline]
pub fn find<F: FnMut(&mut INode)>(root: &mut IVisit, path: &str, mut f: F) -> bool {
find_rec(root, path, &mut f)
}
fn find_rec(list: &mut IVisit, path: &str, f: &mut FnMut(&mut INode)) -> bool {
let mut found = false;
list.visit_mut(&mut |node| {
match ComparePath::cmp(path, node.name()) {
ComparePath::True => {
f(node);
found = true;
},
ComparePath::Part(tail) => {
if let NodeMut::List(list) = node.as_node_mut() {
found |= find_rec(list.as_visit_mut(), tail, f);
}
},
ComparePath::False => {},
};
});
found
}
#[inline]
pub fn walk<F: FnMut(&str, &mut INode)>(root: &mut IVisit, mut f: F) {
let mut path = String::new();
walk_rec(root, &mut path, &mut f);
}
fn walk_rec(list: &mut IVisit, path: &mut String, f: &mut FnMut(&str, &mut INode)) {
list.visit_mut(&mut |node| {
let len = path.len();
if len > 0 {
path.push('.');
}
path.push_str(node.name());
f(&path, node);
if let NodeMut::List(list) = node.as_node_mut() {
walk_rec(list.as_visit_mut(), path, f);
}
path.truncate(len);
});
}
#[inline]
pub fn invoke(root: &mut IVisit, path: &str, args: &[&str], console: &mut IConsole) -> bool {
let mut found = false;
find(root, path, |node| {
if let NodeMut::Action(act) = node.as_node_mut() {
found = true;
act.invoke(args, console);
}
});
found
}