|
3 | 3 |
|
4 | 4 | use std::fmt; |
5 | 5 |
|
| 6 | +pub use vortex_utils::tree::DepthContext as PlanTreeContext; |
| 7 | +pub use vortex_utils::tree::IndentedFormatter as PlanIndentedFormatter; |
| 8 | +use vortex_utils::tree::TreeDisplayAdapter; |
| 9 | +use vortex_utils::tree::write_indented_tree; |
| 10 | + |
6 | 11 | use super::DynPlan; |
7 | 12 | use super::Eval; |
8 | 13 |
|
9 | | -/// Context threaded through a plan tree traversal. |
10 | | -pub struct PlanTreeContext { |
11 | | - depth: usize, |
12 | | -} |
13 | | - |
14 | | -impl PlanTreeContext { |
15 | | - fn new() -> Self { |
16 | | - Self { depth: 0 } |
17 | | - } |
18 | | - |
19 | | - /// Returns the current node's depth, where the root has depth zero. |
20 | | - pub fn depth(&self) -> usize { |
21 | | - self.depth |
22 | | - } |
23 | | - |
24 | | - fn push(&mut self) { |
25 | | - self.depth += 1; |
26 | | - } |
27 | | - |
28 | | - fn pop(&mut self) { |
29 | | - self.depth -= 1; |
30 | | - } |
31 | | -} |
32 | | - |
33 | | -/// Wrapper providing access to a formatter and the current indentation string. |
34 | | -pub struct PlanIndentedFormatter<'a, 'b> { |
35 | | - inner: &'a mut fmt::Formatter<'b>, |
36 | | - indent: &'a str, |
37 | | -} |
38 | | - |
39 | | -impl<'a, 'b> PlanIndentedFormatter<'a, 'b> { |
40 | | - fn new(inner: &'a mut fmt::Formatter<'b>, indent: &'a str) -> Self { |
41 | | - Self { inner, indent } |
42 | | - } |
43 | | - |
44 | | - /// Returns the indentation string and underlying formatter together. |
45 | | - pub fn parts(&mut self) -> (&str, &mut fmt::Formatter<'b>) { |
46 | | - (self.indent, self.inner) |
47 | | - } |
48 | | - |
49 | | - /// Returns the current indentation string. |
50 | | - pub fn indent(&self) -> &str { |
51 | | - self.indent |
52 | | - } |
53 | | - |
54 | | - /// Returns the underlying formatter. |
55 | | - pub fn formatter(&mut self) -> &mut fmt::Formatter<'b> { |
56 | | - self.inner |
57 | | - } |
58 | | -} |
59 | | - |
60 | 14 | /// Contributes one composable dimension of information to plan tree nodes. |
61 | 15 | pub trait PlanTreeExtractor: Send + Sync { |
62 | 16 | /// Writes space-prefixed annotations on the node's header line. |
@@ -163,49 +117,62 @@ impl<'a> PlanTreeDisplay<'a> { |
163 | 117 | self.extractors.push(extractor); |
164 | 118 | self |
165 | 119 | } |
| 120 | +} |
| 121 | + |
| 122 | +impl TreeDisplayAdapter for PlanTreeDisplay<'_> { |
| 123 | + type Context = PlanTreeContext; |
| 124 | + type Node = dyn DynPlan; |
166 | 125 |
|
167 | 126 | fn write_node( |
168 | 127 | &self, |
169 | | - name: &str, |
170 | 128 | plan: &dyn DynPlan, |
171 | | - context: &mut PlanTreeContext, |
172 | | - indent: &str, |
| 129 | + context: &PlanTreeContext, |
173 | 130 | formatter: &mut fmt::Formatter<'_>, |
174 | 131 | ) -> fmt::Result { |
175 | | - write!(formatter, "{indent}{name}:")?; |
176 | 132 | for extractor in &self.extractors { |
177 | 133 | extractor.write_header(plan, context, formatter)?; |
178 | 134 | } |
179 | | - writeln!(formatter)?; |
180 | | - |
181 | | - let child_indent = format!("{indent} "); |
182 | | - { |
183 | | - let mut indented = PlanIndentedFormatter::new(formatter, &child_indent); |
184 | | - for extractor in &self.extractors { |
185 | | - extractor.write_details(plan, context, &mut indented)?; |
186 | | - } |
| 135 | + Ok(()) |
| 136 | + } |
| 137 | + |
| 138 | + fn write_details( |
| 139 | + &self, |
| 140 | + plan: &dyn DynPlan, |
| 141 | + context: &PlanTreeContext, |
| 142 | + formatter: &mut PlanIndentedFormatter<'_, '_>, |
| 143 | + ) -> fmt::Result { |
| 144 | + for extractor in &self.extractors { |
| 145 | + extractor.write_details(plan, context, formatter)?; |
187 | 146 | } |
| 147 | + Ok(()) |
| 148 | + } |
188 | 149 |
|
189 | | - context.push(); |
190 | | - for (index, child) in plan.children().iter().enumerate() { |
| 150 | + fn visit_children( |
| 151 | + &self, |
| 152 | + plan: &dyn DynPlan, |
| 153 | + visit: &mut dyn FnMut(&str, &dyn DynPlan, bool) -> fmt::Result, |
| 154 | + ) -> fmt::Result { |
| 155 | + let children = plan.children(); |
| 156 | + for (index, child) in children.iter().enumerate() { |
191 | 157 | let child_name = plan.child_name(index); |
192 | | - self.write_node( |
| 158 | + visit( |
193 | 159 | child_name.as_ref(), |
194 | 160 | child.as_ref(), |
195 | | - context, |
196 | | - &child_indent, |
197 | | - formatter, |
| 161 | + index + 1 == children.len(), |
198 | 162 | )?; |
199 | 163 | } |
200 | | - context.pop(); |
201 | | - |
202 | 164 | Ok(()) |
203 | 165 | } |
204 | 166 | } |
205 | 167 |
|
206 | 168 | impl fmt::Display for PlanTreeDisplay<'_> { |
207 | 169 | fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { |
208 | | - let mut context = PlanTreeContext::new(); |
209 | | - self.write_node("root", self.plan, &mut context, "", formatter) |
| 170 | + write_indented_tree( |
| 171 | + self, |
| 172 | + "root", |
| 173 | + self.plan, |
| 174 | + &mut PlanTreeContext::default(), |
| 175 | + formatter, |
| 176 | + ) |
210 | 177 | } |
211 | 178 | } |
0 commit comments