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,ignore
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 replacement for `syn::visit::Visit` if the `syn` feature is enabled. Implement `directed_visit::syn::visit::Full` as you would `syn::visit::Visit`.  
24//! 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`.  
25//! In addition to the existing syn AST, two nodes have been added to the tree to represent when generic parameters become in and out of scope.  
26//! The `derive` feature subset of `full` is not yet supported.
27//!
28//! ## Limitations
29//! 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.  
30#![warn(missing_docs)]
31
32mod direct;
33pub use direct::{Direct, Director};
34/// Direct and Visit implementations for the syn AST
35#[cfg(feature = "syn")]
36pub mod syn;
37mod visit;
38pub use visit::{Visit, Visitor};
39
40#[derive(Debug)]
41pub(crate) struct DirectorVisitor<'d, A: ?Sized, V: ?Sized> {
42    pub(crate) direct: &'d mut A,
43    pub(crate) visit: &'d mut V,
44}
45
46impl<A: ?Sized, V: ?Sized> DirectorVisitor<'_, A, V> {
47    pub(crate) fn reborrow(&mut self) -> DirectorVisitor<'_, A, V> {
48        let Self { direct, visit } = self;
49
50        DirectorVisitor { direct, visit }
51    }
52}
53
54/// Perform a visit using a Direct-Visit pair, and a given input.
55pub fn visit<'dv, D, V, N>(direct: &'dv mut D, visit: &'dv mut V, node: &N)
56where
57    D: Direct<V, N> + ?Sized,
58    V: Visit<N> + ?Sized,
59    N: ?Sized,
60{
61    V::visit(Visitor::new(DirectorVisitor { direct, visit }, node), node);
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    struct A(Option<B>);
69    struct B(Vec<C>);
70    struct C(A);
71
72    struct MyDirect;
73    impl crate::Direct<MyVisit, A> for MyDirect {
74        fn direct<'dv>(mut director: Director<'dv, Self, MyVisit>, node: &A) {
75            if let Some(b) = &node.0 {
76                Director::direct(&mut director, b);
77            }
78        }
79    }
80
81    impl crate::Direct<MyVisit, B> for MyDirect {
82        fn direct<'dv>(mut director: Director<'dv, Self, MyVisit>, node: &B) {
83            for c in &node.0 {
84                Director::direct(&mut director, c);
85            }
86        }
87    }
88
89    impl crate::Direct<MyVisit, C> for MyDirect {
90        fn direct<'dv>(mut director: Director<'dv, Self, MyVisit>, node: &C) {
91            Director::direct(&mut director, &node.0)
92        }
93    }
94
95    struct MyVisit(usize);
96    impl crate::Visit<A> for MyVisit {
97        fn visit<'dv, 'n, D: ?Sized>(mut visitor: Visitor<'dv, 'n, D, Self, A>, _node: &'n A)
98        where
99            D: Direct<Self, A>,
100        {
101            visitor.0 += 1;
102            Visitor::visit(visitor);
103        }
104    }
105    impl crate::Visit<B> for MyVisit {
106        fn visit<'dv, 'n, D: ?Sized>(mut visitor: Visitor<'dv, 'n, D, Self, B>, _node: &'n B)
107        where
108            D: Direct<Self, B>,
109        {
110            visitor.0 += 2;
111            Visitor::visit(visitor);
112        }
113    }
114    impl crate::Visit<C> for MyVisit {
115        fn visit<'dv, 'n, D: ?Sized>(mut visitor: Visitor<'dv, 'n, D, Self, C>, _node: &'n C)
116        where
117            D: Direct<Self, C>,
118        {
119            visitor.0 += 3;
120            Visitor::visit(visitor);
121        }
122    }
123
124    #[test]
125    fn custom_node_set() {
126        let input = A(Some(
127            // 1
128            B(vec![
129                // 3
130                C(
131                    // 6
132                    A(None),
133                ), // 7
134                C(
135                    // 10
136                    A(Some(
137                        // 11
138                        B(vec![]), // 13
139                    )),
140                ),
141            ]),
142        ));
143
144        let mut direct = MyDirect;
145        let mut visit = MyVisit(0);
146        crate::visit(&mut direct, &mut visit, &input);
147
148        assert_eq!(visit.0, 13);
149    }
150}