#![cfg(all(feature = "std", feature = "derive"))]
use std::any::Any;
use std::cell::RefCell;
use std::ops::ControlFlow;
use std::rc::Rc;
use traversable::Traversable;
use traversable::TraversableMut;
use traversable::Visitor;
use traversable::VisitorMut;
use traversable::combinator::VisitorExt;
use traversable::combinator::VisitorMutExt;
#[derive(Traversable, TraversableMut)]
struct Data {
val: i32,
child: Option<Box<Data>>,
}
#[derive(Clone)]
struct RecordVisitor {
log: Rc<RefCell<Vec<String>>>,
name: String,
break_on: Option<i32>,
}
impl Visitor for RecordVisitor {
type Break = i32;
fn enter(&mut self, this: &dyn Any) -> ControlFlow<Self::Break> {
if let Some(d) = this.downcast_ref::<Data>() {
self.log
.borrow_mut()
.push(format!("{}: enter {}", self.name, d.val));
if Some(d.val) == self.break_on {
return ControlFlow::Break(d.val);
}
}
ControlFlow::Continue(())
}
fn leave(&mut self, this: &dyn Any) -> ControlFlow<Self::Break> {
if let Some(d) = this.downcast_ref::<Data>() {
self.log
.borrow_mut()
.push(format!("{}: leave {}", self.name, d.val));
}
ControlFlow::Continue(())
}
}
#[test]
fn test_visitor_or() {
let data = Data {
val: 1,
child: Some(Box::new(Data {
val: 2,
child: None,
})),
};
let log = Rc::new(RefCell::new(Vec::new()));
let v1 = RecordVisitor {
log: log.clone(),
name: "v1".to_string(),
break_on: None,
};
let v2 = RecordVisitor {
log: log.clone(),
name: "v2".to_string(),
break_on: None,
};
let mut combined = v1.chain(v2);
let result = data.traverse(&mut combined);
assert!(result.is_continue());
let expected = vec![
"v1: enter 1",
"v2: enter 1",
"v1: enter 2",
"v2: enter 2",
"v1: leave 2",
"v2: leave 2",
"v1: leave 1",
"v2: leave 1",
];
assert_eq!(*log.borrow(), expected);
}
#[test]
fn test_visitor_or_break_v1() {
let data = Data {
val: 1,
child: Some(Box::new(Data {
val: 2,
child: None,
})),
};
let log = Rc::new(RefCell::new(Vec::new()));
let v1 = RecordVisitor {
log: log.clone(),
name: "v1".to_string(),
break_on: Some(2),
};
let v2 = RecordVisitor {
log: log.clone(),
name: "v2".to_string(),
break_on: None,
};
let mut combined = v1.chain(v2);
let result = data.traverse(&mut combined);
assert_eq!(result, ControlFlow::Break(2));
let expected = vec![
"v1: enter 1",
"v2: enter 1",
"v1: enter 2", ];
assert_eq!(*log.borrow(), expected);
}
#[test]
fn test_visitor_or_break_v2() {
let data = Data {
val: 1,
child: Some(Box::new(Data {
val: 2,
child: None,
})),
};
let log = Rc::new(RefCell::new(Vec::new()));
let v1 = RecordVisitor {
log: log.clone(),
name: "v1".to_string(),
break_on: None,
};
let v2 = RecordVisitor {
log: log.clone(),
name: "v2".to_string(),
break_on: Some(2),
};
let mut combined = v1.chain(v2);
let result = data.traverse(&mut combined);
assert_eq!(result, ControlFlow::Break(2));
let expected = vec![
"v1: enter 1",
"v2: enter 1",
"v1: enter 2",
"v2: enter 2", ];
assert_eq!(*log.borrow(), expected);
}
struct MutVisitor {
val_multiplier: i32,
}
impl VisitorMut for MutVisitor {
type Break = ();
fn enter_mut(&mut self, this: &mut dyn Any) -> ControlFlow<()> {
if let Some(d) = this.downcast_mut::<Data>() {
d.val *= self.val_multiplier;
}
ControlFlow::Continue(())
}
}
#[test]
fn test_visitor_mut_or() {
let mut data = Data {
val: 1,
child: Some(Box::new(Data {
val: 2,
child: None,
})),
};
let v1 = MutVisitor { val_multiplier: 2 };
let v2 = MutVisitor { val_multiplier: 3 };
let mut combined = v1.chain(v2);
let result = data.traverse_mut(&mut combined);
assert!(result.is_continue());
assert_eq!(data.val, 6);
assert_eq!(data.child.unwrap().val, 12);
}