directed_visit/lib.rs
1//! Implement the visitor pattern with interchangable implementations for both the visit algorithm and node object traversal. It is also possible to dynamically create temporary 'virtual' nodes during traversal.
2//!
3//! An object traversal is comprised of 3 parts:
4//! The input to traverse, which can start at any node type. This can be an external type too, there are no required derives or trait impls.
5//! The director navigates between node objects. It must implement `Direct<N>` for each node type `N` in the object graph, determining the sub-nodes.
6//! The visitor performs the desired algorithm, implementing `Visit<N>` for each node type `N` in the object graph.
7//!
8//! ```rust
9//! fn my_visit(input: &MyTree) -> usize {
10//! let mut my_director = MyDirector::new();
11//! let mut my_visitor = MyVisitor::new();
12//! directed_visit::visit(
13//! &mut my_director,
14//! &mut my_visitor,
15//! input,
16//! );
17//!
18//! my_visitor.result_value()
19//! }
20//! ```
21//!
22//! ## syn
23//! The crate includes a low-pain replacement for `syn::visit::Visit` if the `syn` feature is enabled. Implement `directed_visit::syn::visit::Full` as you would `syn::visit::Visit`. For your director, `directed_visit::syn::direct::FullDefault` traverses as `syn::visit` does, or you can customize the behavior by implementing `directed_visit::syn::direct::Full`. The `derive` feature subset of `full` is not yet supported.
24//!
25//! ## Limitations
26//! Because the director can dynamically create new nodes to visit, the visitor cannot hold references to the node graph (i.e. there is no single `'ast` lifetime for all nodes). For this reason there is also currently no `VisitMut` equivalent, because the ideal interaction between handling temporary dynamic nodes and mutating them is unclear.
27#![warn(missing_docs)]
28
29mod direct;
30pub use direct::{Direct, Director};
31#[cfg(feature = "syn")]
32pub mod syn;
33mod visit;
34pub use visit::{Visit, Visitor};
35
36#[derive(Debug)]
37pub(crate) struct DirectorVisitor<'d, A: ?Sized, V: ?Sized> {
38 pub(crate) direct: &'d mut A,
39 pub(crate) visit: &'d mut V,
40}
41
42impl<A: ?Sized, V: ?Sized> DirectorVisitor<'_, A, V> {
43 pub(crate) fn reborrow(&mut self) -> DirectorVisitor<'_, A, V> {
44 let Self {
45 direct,
46 visit,
47 } = self;
48
49 DirectorVisitor {
50 direct,
51 visit,
52 }
53 }
54}
55
56/// Perform a visit using a Direct-Visit pair, and a given input.
57pub fn visit<'dv, D, V, N>(direct: &'dv mut D, visit: &'dv mut V, node: &N)
58where
59 D: Direct<V, N> + ?Sized,
60 V: Visit<N> + ?Sized,
61 N: ?Sized,
62{
63 V::visit(
64 Visitor::new(
65 DirectorVisitor {
66 direct,
67 visit,
68 },
69 node
70 ),
71 node
72 );
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 struct A(Option<B>);
80 struct B(Vec<C>);
81 struct C(A);
82
83 struct MyDirect;
84 impl crate::Direct<MyVisit, A> for MyDirect {
85 fn direct<'dv>(mut director: Director<'dv, Self, MyVisit>, node: &A) {
86 if let Some(b) = &node.0 {
87 Director::direct(&mut director, b);
88 }
89 }
90 }
91
92 impl crate::Direct<MyVisit, B> for MyDirect {
93 fn direct<'dv>(mut director: Director<'dv, Self, MyVisit>, node: &B) {
94 for c in &node.0 {
95 Director::direct(&mut director, c);
96 }
97 }
98 }
99
100 impl crate::Direct<MyVisit, C> for MyDirect {
101 fn direct<'dv>(mut director: Director<'dv, Self, MyVisit>, node: &C) {
102 Director::direct(&mut director, &node.0)
103 }
104 }
105
106 struct MyVisit(usize);
107 impl crate::Visit<A> for MyVisit {
108 fn visit<'dv, 'n, D: ?Sized>(mut visitor: Visitor<'dv, 'n, D, Self, A>, _node: &'n A)
109 where
110 D: Direct<Self, A>,
111 {
112 visitor.0 += 1;
113 Visitor::visit(visitor);
114 }
115 }
116 impl crate::Visit<B> for MyVisit {
117 fn visit<'dv, 'n, D: ?Sized>(mut visitor: Visitor<'dv, 'n, D, Self, B>, _node: &'n B)
118 where
119 D: Direct<Self, B>,
120 {
121 visitor.0 += 2;
122 Visitor::visit(visitor);
123 }
124 }
125 impl crate::Visit<C> for MyVisit {
126 fn visit<'dv, 'n, D: ?Sized>(mut visitor: Visitor<'dv, 'n, D, Self, C>, _node: &'n C)
127 where
128 D: Direct<Self, C>,
129 {
130 visitor.0 += 3;
131 Visitor::visit(visitor);
132 }
133 }
134
135 #[test]
136 fn custom_node_set() {
137 let input =
138 A(Some( // 1
139 B(vec![ // 3
140 C( // 6
141 A(None)) // 7
142 ,
143 C( // 10
144 A(Some( // 11
145 B(vec![]) // 13
146 ))
147 )
148 ])
149 ));
150
151 let mut direct = MyDirect;
152 let mut visit = MyVisit(0);
153 crate::visit(&mut direct, &mut visit, &input);
154
155 assert_eq!(visit.0, 13);
156 }
157}