substrait_explain/textify/
extensions.rs1use std::fmt;
9
10use substrait::proto::{ExtensionLeafRel, ExtensionMultiRel, ExtensionSingleRel};
11
12use crate::extensions::any::AnyRef;
13use crate::extensions::registry::ExtensionError;
14use crate::extensions::{ExtensionArgs, ExtensionColumn, ExtensionValue};
15use crate::textify::foundation::{Scope, Textify};
16use crate::textify::types::escaped;
17
18fn format_extension<S: Scope, W: fmt::Write>(
20 ctx: &S,
21 w: &mut W,
22 extension_type: &str,
23 detail: Option<AnyRef<'_>>,
24) -> fmt::Result {
25 let indent = ctx.indent();
26
27 match detail {
28 Some(detail) => {
29 let registry = ctx.extension_registry();
31 match registry.decode(detail) {
32 Ok((name, args)) => {
33 write!(
35 w,
36 "{}{}:{}[{}]",
37 indent,
38 extension_type,
39 name,
40 ctx.display(&args)
41 )?;
42 }
43 Err(error) => {
44 write!(w, "{}{}[{}]", indent, extension_type, ctx.failure(error))?;
46 }
47 }
48 }
49 None => {
50 let error = ExtensionError::MissingDetail;
52 write!(w, "{}{}[{}]", indent, extension_type, ctx.failure(error))?;
53 }
54 }
55
56 Ok(())
57}
58
59impl Textify for ExtensionValue {
60 fn name() -> &'static str {
61 "ExtensionValue"
62 }
63
64 fn textify<S: Scope, W: fmt::Write>(&self, _ctx: &S, w: &mut W) -> fmt::Result {
65 match self {
66 ExtensionValue::String(s) => write!(w, "'{}'", escaped(s)),
67 ExtensionValue::Integer(i) => write!(w, "{i}"),
68 ExtensionValue::Float(f) => write!(w, "{f}"),
69 ExtensionValue::Boolean(b) => write!(w, "{b}"),
70 ExtensionValue::Reference(r) => write!(w, "${r}"),
71 ExtensionValue::Expression(e) => write!(w, "{e}"),
72 }
73 }
74}
75
76impl Textify for ExtensionColumn {
77 fn name() -> &'static str {
78 "ExtensionColumn"
79 }
80
81 fn textify<S: Scope, W: fmt::Write>(&self, _ctx: &S, w: &mut W) -> fmt::Result {
82 match self {
83 ExtensionColumn::Named { name, type_spec } => write!(w, "{name}:{type_spec}"),
84 ExtensionColumn::Reference(r) => write!(w, "${r}"),
85 ExtensionColumn::Expression(e) => write!(w, "{e}"),
86 }
87 }
88}
89
90impl Textify for ExtensionArgs {
91 fn name() -> &'static str {
92 "ExtensionArgs"
93 }
94
95 fn textify<S: Scope, W: fmt::Write>(&self, ctx: &S, w: &mut W) -> fmt::Result {
96 let mut has_args = false;
97
98 for (i, value) in self.positional.iter().enumerate() {
100 if i > 0 || has_args {
101 write!(w, ", ")?;
102 }
103 value.textify(ctx, w)?;
104 has_args = true;
105 }
106
107 for (name, value) in &self.named {
109 if has_args {
110 write!(w, ", ")?;
111 }
112 write!(w, "{name}=")?;
113 value.textify(ctx, w)?;
114 has_args = true;
115 }
116
117 if !has_args {
118 write!(w, "_")?;
119 }
120
121 if !self.output_columns.is_empty() {
123 write!(w, " => {}", ctx.separated(self.output_columns.iter(), ", "))?;
124 }
125
126 Ok(())
127 }
128}
129
130fn textify_children<S: Scope, W: fmt::Write>(
132 ctx: &S,
133 w: &mut W,
134 children: &[substrait::proto::Rel],
135) -> fmt::Result {
136 let child_scope = ctx.push_indent();
137 for child in children {
138 writeln!(w)?;
139 child.textify(&child_scope, w)?;
140 }
141 Ok(())
142}
143
144fn textify_child<S: Scope, W: fmt::Write>(
146 ctx: &S,
147 w: &mut W,
148 child: Option<&substrait::proto::Rel>,
149) -> fmt::Result {
150 if let Some(input) = child {
151 let child_scope = ctx.push_indent();
152 writeln!(w)?;
153 input.textify(&child_scope, w)?;
154 }
155 Ok(())
156}
157
158impl Textify for ExtensionLeafRel {
159 fn name() -> &'static str {
160 "ExtensionLeafRel"
161 }
162
163 fn textify<S: Scope, W: fmt::Write>(&self, ctx: &S, w: &mut W) -> fmt::Result {
164 let detail_ref = self.detail.as_ref().map(AnyRef::from);
166 format_extension(ctx, w, "ExtensionLeaf", detail_ref)
167 }
168}
169
170impl Textify for ExtensionSingleRel {
171 fn name() -> &'static str {
172 "ExtensionSingleRel"
173 }
174
175 fn textify<S: Scope, W: fmt::Write>(&self, ctx: &S, w: &mut W) -> fmt::Result {
176 let detail_ref = self.detail.as_ref().map(AnyRef::from);
178 format_extension(ctx, w, "ExtensionSingle", detail_ref)?;
179
180 textify_child(ctx, w, self.input.as_deref())?;
182 Ok(())
183 }
184}
185
186impl Textify for ExtensionMultiRel {
187 fn name() -> &'static str {
188 "ExtensionMultiRel"
189 }
190
191 fn textify<S: Scope, W: fmt::Write>(&self, ctx: &S, w: &mut W) -> fmt::Result {
192 let detail_ref = self.detail.as_ref().map(AnyRef::from);
194 format_extension(ctx, w, "ExtensionMulti", detail_ref)?;
195
196 textify_children(ctx, w, &self.inputs)?;
198 Ok(())
199 }
200}