## Coverage Report

#### Created: 2024-10-13 08:39

    /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
    }