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}