/Users/andrewlamb/Software/datafusion/datafusion/physical-plan/src/visitor.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | use super::ExecutionPlan; |
19 | | |
20 | | /// Visit all children of this plan, according to the order defined on `ExecutionPlanVisitor`. |
21 | | // Note that this would be really nice if it were a method on |
22 | | // ExecutionPlan, but it can not be because it takes a generic |
23 | | // parameter and `ExecutionPlan` is a trait |
24 | 5 | pub fn accept<V: ExecutionPlanVisitor>( |
25 | 5 | plan: &dyn ExecutionPlan, |
26 | 5 | visitor: &mut V, |
27 | 5 | ) -> Result<(), V::Error> { |
28 | 5 | visitor.pre_visit(plan)?0 ; |
29 | 5 | for child in plan.children() { |
30 | 5 | visit_execution_plan(child.as_ref(), visitor)?0 ; |
31 | | } |
32 | 5 | visitor.post_visit(plan)?0 ; |
33 | 5 | Ok(()) |
34 | 5 | } |
35 | | |
36 | | /// Trait that implements the [Visitor |
37 | | /// pattern](https://en.wikipedia.org/wiki/Visitor_pattern) for a |
38 | | /// depth first walk of `ExecutionPlan` nodes. `pre_visit` is called |
39 | | /// before any children are visited, and then `post_visit` is called |
40 | | /// after all children have been visited. |
41 | | /// |
42 | | /// To use, define a struct that implements this trait and then invoke |
43 | | /// ['accept']. |
44 | | /// |
45 | | /// For example, for an execution plan that looks like: |
46 | | /// |
47 | | /// ```text |
48 | | /// ProjectionExec: id |
49 | | /// FilterExec: state = CO |
50 | | /// CsvExec: |
51 | | /// ``` |
52 | | /// |
53 | | /// The sequence of visit operations would be: |
54 | | /// ```text |
55 | | /// visitor.pre_visit(ProjectionExec) |
56 | | /// visitor.pre_visit(FilterExec) |
57 | | /// visitor.pre_visit(CsvExec) |
58 | | /// visitor.post_visit(CsvExec) |
59 | | /// visitor.post_visit(FilterExec) |
60 | | /// visitor.post_visit(ProjectionExec) |
61 | | /// ``` |
62 | | pub trait ExecutionPlanVisitor { |
63 | | /// The type of error returned by this visitor |
64 | | type Error; |
65 | | |
66 | | /// Invoked on an `ExecutionPlan` plan before any of its child |
67 | | /// inputs have been visited. If Ok(true) is returned, the |
68 | | /// recursion continues. If Err(..) or Ok(false) are returned, the |
69 | | /// recursion stops immediately and the error, if any, is returned |
70 | | /// to `accept` |
71 | | fn pre_visit(&mut self, plan: &dyn ExecutionPlan) -> Result<bool, Self::Error>; |
72 | | |
73 | | /// Invoked on an `ExecutionPlan` plan *after* all of its child |
74 | | /// inputs have been visited. The return value is handled the same |
75 | | /// as the return value of `pre_visit`. The provided default |
76 | | /// implementation returns `Ok(true)`. |
77 | 0 | fn post_visit(&mut self, _plan: &dyn ExecutionPlan) -> Result<bool, Self::Error> { |
78 | 0 | Ok(true) |
79 | 0 | } |
80 | | } |
81 | | |
82 | | /// Recursively calls `pre_visit` and `post_visit` for this node and |
83 | | /// all of its children, as described on [`ExecutionPlanVisitor`] |
84 | 10 | pub fn visit_execution_plan<V: ExecutionPlanVisitor>( |
85 | 10 | plan: &dyn ExecutionPlan, |
86 | 10 | visitor: &mut V, |
87 | 10 | ) -> Result<(), V::Error> { |
88 | 10 | visitor.pre_visit(plan)?0 ; |
89 | 10 | for child5 in plan.children() { |
90 | 5 | visit_execution_plan(child.as_ref(), visitor)?0 ; |
91 | | } |
92 | 10 | visitor.post_visit(plan)?0 ; |
93 | 10 | Ok(()) |
94 | 10 | } |