Skip to main content

substrait_explain/textify/
extensions.rs

1//! Extension textification support
2//!
3//! This module provides [`Textify`] implementations for extension-related
4//! types, including [`ExtensionValue`], [`ExtensionColumn`], [`ExtensionArgs`],
5//! and the various extension relation types ([`substrait::proto::ExtensionLeafRel`],
6//! [`substrait::proto::ExtensionSingleRel`], [`substrait::proto::ExtensionMultiRel`]).
7
8use std::fmt;
9
10use crate::extensions::{Expr, ExtensionArgs, ExtensionColumn, ExtensionValue, TupleValue};
11use crate::textify::foundation::{Scope, Textify};
12use crate::textify::types::{Name, escaped};
13
14impl Textify for TupleValue {
15    fn name() -> &'static str {
16        "TupleValue"
17    }
18
19    fn textify<S: Scope, W: fmt::Write>(&self, ctx: &S, w: &mut W) -> fmt::Result {
20        write!(w, "(")?;
21        if self.len() == 1 {
22            self.iter().next().unwrap().textify(ctx, w)?;
23            write!(w, ",")?;
24        } else {
25            write!(w, "{}", ctx.separated(self, ", "))?;
26        }
27        write!(w, ")")
28    }
29}
30
31impl Textify for ExtensionValue {
32    fn name() -> &'static str {
33        "ExtensionValue"
34    }
35
36    fn textify<S: Scope, W: fmt::Write>(&self, ctx: &S, w: &mut W) -> fmt::Result {
37        match self {
38            ExtensionValue::String(s) => write!(w, "'{}'", escaped(s)),
39            ExtensionValue::Integer(i) => write!(w, "{i}"),
40            ExtensionValue::Float(f) => write!(w, "{f}"),
41            ExtensionValue::Boolean(b) => write!(w, "{b}"),
42            ExtensionValue::Expr(expr) => expr.textify(ctx, w),
43            ExtensionValue::Enum(e) => write!(w, "&{e}"),
44            ExtensionValue::Tuple(tv) => tv.textify(ctx, w),
45        }
46    }
47}
48
49impl Textify for Expr {
50    fn name() -> &'static str {
51        "Expr"
52    }
53
54    fn textify<S: Scope, W: fmt::Write>(&self, ctx: &S, w: &mut W) -> fmt::Result {
55        write!(w, "{}", ctx.display(self.as_proto()))
56    }
57}
58
59impl Textify for ExtensionColumn {
60    fn name() -> &'static str {
61        "ExtensionColumn"
62    }
63
64    fn textify<S: Scope, W: fmt::Write>(&self, ctx: &S, w: &mut W) -> fmt::Result {
65        match self {
66            ExtensionColumn::Named { name, r#type: ty } => {
67                write!(w, "{}:{}", Name(name), ctx.display(ty))
68            }
69            ExtensionColumn::Expr(expr) => expr.textify(ctx, w),
70        }
71    }
72}
73
74impl Textify for ExtensionArgs {
75    fn name() -> &'static str {
76        "ExtensionArgs"
77    }
78
79    fn textify<S: Scope, W: fmt::Write>(&self, ctx: &S, w: &mut W) -> fmt::Result {
80        let mut has_args = false;
81
82        // Add positional arguments
83        for (i, value) in self.positional.iter().enumerate() {
84            if i > 0 || has_args {
85                write!(w, ", ")?;
86            }
87            value.textify(ctx, w)?;
88            has_args = true;
89        }
90
91        // Add named arguments in display order (IndexMap preserves insertion order)
92        for (name, value) in &self.named {
93            if has_args {
94                write!(w, ", ")?;
95            }
96            write!(w, "{name}=")?;
97            value.textify(ctx, w)?;
98            has_args = true;
99        }
100
101        if !has_args {
102            write!(w, "_")?;
103        }
104
105        // Add output columns if present
106        if !self.output_columns.is_empty() {
107            write!(w, " => {}", ctx.separated(self.output_columns.iter(), ", "))?;
108        }
109
110        Ok(())
111    }
112}