substrait_explain/extensions/
args.rs1use std::collections::HashSet;
29use std::slice::Iter as SliceIter;
30use std::vec::IntoIter as VecIntoIter;
31use std::{fmt, thread};
32
33use indexmap::IndexMap;
34use substrait::proto;
35use substrait::proto::expression::field_reference::ReferenceType;
36use substrait::proto::expression::literal::LiteralType;
37use substrait::proto::expression::{RexType, reference_segment};
38
39use super::ExtensionError;
40use crate::textify::expressions::Reference;
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48pub(crate) enum AddendumKind {
49 Enhancement,
50 Optimization,
51 ExtensionTable,
52}
53
54impl AddendumKind {
55 pub(crate) fn prefix(self) -> &'static str {
56 match self {
57 AddendumKind::Enhancement => "Enh",
58 AddendumKind::Optimization => "Opt",
59 AddendumKind::ExtensionTable => "Ext",
60 }
61 }
62}
63
64#[derive(Debug, Clone)]
69pub struct Expr(Box<proto::Expression>);
70
71impl Expr {
72 pub fn field(index: i32) -> Self {
74 Reference(index).into()
75 }
76
77 pub fn as_proto(&self) -> &proto::Expression {
79 self.0.as_ref()
80 }
81
82 pub fn to_proto(&self) -> proto::Expression {
84 self.as_proto().clone()
85 }
86
87 pub fn as_direct_reference(&self) -> Option<i32> {
89 let Some(RexType::Selection(field_ref)) = self.as_proto().rex_type.as_ref() else {
90 return None;
91 };
92 let Some(ReferenceType::DirectReference(segment)) = field_ref.reference_type.as_ref()
93 else {
94 return None;
95 };
96 let Some(reference_segment::ReferenceType::StructField(field)) =
97 segment.reference_type.as_ref()
98 else {
99 return None;
100 };
101 if field.child.is_some() {
102 return None;
103 }
104 Some(field.field)
105 }
106}
107
108impl From<proto::Expression> for Expr {
109 fn from(expr: proto::Expression) -> Self {
110 Expr(Box::new(expr))
111 }
112}
113
114impl From<proto::expression::Literal> for Expr {
115 fn from(literal: proto::expression::Literal) -> Self {
116 proto::Expression {
117 rex_type: Some(RexType::Literal(literal)),
118 }
119 .into()
120 }
121}
122
123impl From<Reference> for Expr {
124 fn from(reference: Reference) -> Self {
125 proto::Expression::from(reference).into()
126 }
127}
128
129impl From<Expr> for proto::Expression {
130 fn from(expr: Expr) -> Self {
131 *expr.0
132 }
133}
134
135impl From<i64> for Expr {
136 fn from(value: i64) -> Self {
137 proto::expression::Literal {
138 literal_type: Some(LiteralType::I64(value)),
139 nullable: false,
140 type_variation_reference: 0,
141 }
142 .into()
143 }
144}
145
146impl From<f64> for Expr {
147 fn from(value: f64) -> Self {
148 proto::expression::Literal {
149 literal_type: Some(LiteralType::Fp64(value)),
150 nullable: false,
151 type_variation_reference: 0,
152 }
153 .into()
154 }
155}
156
157impl From<bool> for Expr {
158 fn from(value: bool) -> Self {
159 proto::expression::Literal {
160 literal_type: Some(LiteralType::Boolean(value)),
161 nullable: false,
162 type_variation_reference: 0,
163 }
164 .into()
165 }
166}
167
168impl From<String> for Expr {
169 fn from(value: String) -> Self {
170 proto::expression::Literal {
171 literal_type: Some(LiteralType::String(value)),
172 nullable: false,
173 type_variation_reference: 0,
174 }
175 .into()
176 }
177}
178
179impl From<&str> for Expr {
180 fn from(value: &str) -> Self {
181 value.to_string().into()
182 }
183}
184
185#[derive(Debug, Clone, Default)]
192pub struct ExtensionArgs {
193 pub positional: Vec<ExtensionValue>,
195 pub named: IndexMap<String, ExtensionValue>,
197 pub output_columns: Vec<ExtensionColumn>,
199}
200
201pub struct ArgsExtractor<'a> {
209 args: &'a ExtensionArgs,
210 consumed: HashSet<&'a str>,
211 checked: bool,
212}
213
214impl<'a> ArgsExtractor<'a> {
215 pub fn new(args: &'a ExtensionArgs) -> Self {
217 Self {
218 args,
219 consumed: HashSet::new(),
220 checked: false,
221 }
222 }
223
224 pub fn get_named_arg(&mut self, name: &str) -> Option<&'a ExtensionValue> {
226 match self.args.named.get_key_value(name) {
227 Some((k, value)) => {
228 self.consumed.insert(k);
229 Some(value)
230 }
231 None => None,
232 }
233 }
234
235 pub fn expect_named_arg<T>(&mut self, name: &str) -> Result<T, ExtensionError>
238 where
239 T: TryFrom<&'a ExtensionValue>,
240 T::Error: Into<ExtensionError>,
241 {
242 match self.get_named_arg(name) {
243 Some(value) => T::try_from(value).map_err(Into::into),
244 None => Err(ExtensionError::MissingArgument {
245 name: name.to_string(),
246 }),
247 }
248 }
249
250 pub fn get_named_or<T>(&mut self, name: &str, default: T) -> Result<T, ExtensionError>
253 where
254 T: TryFrom<&'a ExtensionValue>,
255 T::Error: Into<ExtensionError>,
256 {
257 match self.get_named_arg(name) {
258 Some(value) => T::try_from(value).map_err(Into::into),
259 None => Ok(default),
260 }
261 }
262
263 pub fn check_exhausted(&mut self) -> Result<(), ExtensionError> {
270 self.checked = true;
271
272 let mut unknown_args = Vec::new();
273 for name in self.args.named.keys() {
274 if !self.consumed.contains(name.as_str()) {
275 unknown_args.push(name.as_str());
276 }
277 }
278
279 if unknown_args.is_empty() {
280 Ok(())
281 } else {
282 unknown_args.sort();
284 Err(ExtensionError::InvalidArgument(format!(
285 "Unknown named arguments: {}",
286 unknown_args.join(", ")
287 )))
288 }
289 }
290}
291
292impl Drop for ArgsExtractor<'_> {
293 fn drop(&mut self) {
294 if self.checked || thread::panicking() {
295 return;
296 }
297 debug_assert!(
299 false,
300 "ArgsExtractor dropped without calling check_exhausted()"
301 );
302 }
303}
304
305#[derive(Debug, Clone)]
310pub struct TupleValue(Vec<ExtensionValue>);
311
312impl TupleValue {
313 pub fn len(&self) -> usize {
314 self.0.len()
315 }
316
317 pub fn is_empty(&self) -> bool {
318 self.0.is_empty()
319 }
320
321 pub fn iter(&self) -> SliceIter<'_, ExtensionValue> {
322 self.0.iter()
323 }
324}
325
326impl<'a> IntoIterator for &'a TupleValue {
327 type Item = &'a ExtensionValue;
328 type IntoIter = SliceIter<'a, ExtensionValue>;
329
330 fn into_iter(self) -> Self::IntoIter {
331 self.0.iter()
332 }
333}
334
335impl IntoIterator for TupleValue {
336 type Item = ExtensionValue;
337 type IntoIter = VecIntoIter<ExtensionValue>;
338
339 fn into_iter(self) -> Self::IntoIter {
340 self.0.into_iter()
341 }
342}
343
344impl FromIterator<ExtensionValue> for TupleValue {
345 fn from_iter<I: IntoIterator<Item = ExtensionValue>>(iter: I) -> Self {
346 TupleValue(iter.into_iter().collect())
347 }
348}
349
350impl From<Vec<ExtensionValue>> for TupleValue {
351 fn from(items: Vec<ExtensionValue>) -> Self {
352 TupleValue(items)
353 }
354}
355
356#[derive(Debug, Clone)]
362pub enum ExtensionValue {
363 String(String),
367 Integer(i64),
368 Float(f64),
369 Boolean(bool),
370
371 Expr(Expr),
376 Enum(String),
379 Tuple(TupleValue),
381 }
385
386#[derive(Debug, Clone, Copy, PartialEq, Eq)]
388pub enum ExtensionValueKind {
389 String,
390 Integer,
391 Float,
392 Boolean,
393 Reference,
394 Enum,
395 Tuple,
396 Expression,
397}
398
399impl fmt::Display for ExtensionValueKind {
400 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
401 match self {
402 ExtensionValueKind::String => write!(f, "string"),
403 ExtensionValueKind::Integer => write!(f, "integer"),
404 ExtensionValueKind::Float => write!(f, "float"),
405 ExtensionValueKind::Boolean => write!(f, "boolean"),
406 ExtensionValueKind::Reference => write!(f, "reference"),
407 ExtensionValueKind::Enum => write!(f, "enum"),
408 ExtensionValueKind::Tuple => write!(f, "tuple"),
409 ExtensionValueKind::Expression => write!(f, "expression"),
410 }
411 }
412}
413
414impl ExtensionValue {
415 pub fn kind(&self) -> ExtensionValueKind {
417 match self {
418 ExtensionValue::String(_) => ExtensionValueKind::String,
419 ExtensionValue::Integer(_) => ExtensionValueKind::Integer,
420 ExtensionValue::Float(_) => ExtensionValueKind::Float,
421 ExtensionValue::Boolean(_) => ExtensionValueKind::Boolean,
422 ExtensionValue::Expr(_) => ExtensionValueKind::Expression,
423 ExtensionValue::Enum(_) => ExtensionValueKind::Enum,
424 ExtensionValue::Tuple(_) => ExtensionValueKind::Tuple,
425 }
426 }
427}
428
429impl From<Expr> for ExtensionValue {
430 fn from(expr: Expr) -> Self {
431 ExtensionValue::Expr(expr)
432 }
433}
434
435impl From<proto::Expression> for ExtensionValue {
436 fn from(expr: proto::Expression) -> Self {
437 Expr::from(expr).into()
438 }
439}
440
441impl From<proto::expression::Literal> for ExtensionValue {
442 fn from(literal: proto::expression::Literal) -> Self {
443 Expr::from(literal).into()
444 }
445}
446
447impl From<Reference> for ExtensionValue {
448 fn from(reference: Reference) -> Self {
449 Expr::from(reference).into()
450 }
451}
452
453impl From<i64> for ExtensionValue {
454 fn from(value: i64) -> Self {
455 ExtensionValue::Integer(value)
456 }
457}
458
459impl From<f64> for ExtensionValue {
460 fn from(value: f64) -> Self {
461 ExtensionValue::Float(value)
462 }
463}
464
465impl From<bool> for ExtensionValue {
466 fn from(value: bool) -> Self {
467 ExtensionValue::Boolean(value)
468 }
469}
470
471impl From<String> for ExtensionValue {
472 fn from(value: String) -> Self {
473 ExtensionValue::String(value)
474 }
475}
476
477impl From<&str> for ExtensionValue {
478 fn from(value: &str) -> Self {
479 ExtensionValue::String(value.to_string())
480 }
481}
482
483fn invalid_type(expected: ExtensionValueKind, actual: &ExtensionValue) -> ExtensionError {
484 ExtensionError::InvalidArgumentType {
485 expected,
486 actual: actual.kind(),
487 }
488}
489
490impl<'a> TryFrom<&'a ExtensionValue> for &'a str {
491 type Error = ExtensionError;
492
493 fn try_from(value: &'a ExtensionValue) -> Result<&'a str, Self::Error> {
494 match value {
495 ExtensionValue::String(s) => Ok(s),
496 v => Err(invalid_type(ExtensionValueKind::String, v)),
497 }
498 }
499}
500
501impl TryFrom<ExtensionValue> for String {
502 type Error = ExtensionError;
503
504 fn try_from(value: ExtensionValue) -> Result<String, Self::Error> {
505 <&str>::try_from(&value).map(ToOwned::to_owned)
506 }
507}
508
509pub struct EnumValue(pub String);
511
512impl<'a> TryFrom<&'a ExtensionValue> for EnumValue {
513 type Error = ExtensionError;
514
515 fn try_from(value: &'a ExtensionValue) -> Result<EnumValue, Self::Error> {
516 match value {
517 ExtensionValue::Enum(s) => Ok(EnumValue(s.clone())),
518 v => Err(invalid_type(ExtensionValueKind::Enum, v)),
519 }
520 }
521}
522
523impl<'a> TryFrom<&'a ExtensionValue> for &'a TupleValue {
524 type Error = ExtensionError;
525
526 fn try_from(value: &'a ExtensionValue) -> Result<&'a TupleValue, Self::Error> {
527 match value {
528 ExtensionValue::Tuple(tv) => Ok(tv),
529 v => Err(invalid_type(ExtensionValueKind::Tuple, v)),
530 }
531 }
532}
533
534impl TryFrom<&ExtensionValue> for i64 {
535 type Error = ExtensionError;
536
537 fn try_from(value: &ExtensionValue) -> Result<i64, Self::Error> {
538 match value {
539 ExtensionValue::Integer(i) => Ok(*i),
540 v => Err(invalid_type(ExtensionValueKind::Integer, v)),
541 }
542 }
543}
544
545impl TryFrom<&ExtensionValue> for f64 {
546 type Error = ExtensionError;
547
548 fn try_from(value: &ExtensionValue) -> Result<f64, Self::Error> {
549 match value {
550 ExtensionValue::Float(f) => Ok(*f),
551 v => Err(invalid_type(ExtensionValueKind::Float, v)),
552 }
553 }
554}
555
556impl TryFrom<&ExtensionValue> for bool {
557 type Error = ExtensionError;
558
559 fn try_from(value: &ExtensionValue) -> Result<bool, Self::Error> {
560 match value {
561 ExtensionValue::Boolean(b) => Ok(*b),
562 v => Err(invalid_type(ExtensionValueKind::Boolean, v)),
563 }
564 }
565}
566
567impl TryFrom<&ExtensionValue> for Reference {
568 type Error = ExtensionError;
569
570 fn try_from(value: &ExtensionValue) -> Result<Reference, Self::Error> {
571 match value {
572 ExtensionValue::Expr(expr) => expr
573 .as_direct_reference()
574 .map(Reference)
575 .ok_or_else(|| invalid_type(ExtensionValueKind::Reference, value)),
576 v => Err(invalid_type(ExtensionValueKind::Reference, v)),
577 }
578 }
579}
580
581impl TryFrom<&ExtensionValue> for Expr {
582 type Error = ExtensionError;
583
584 fn try_from(value: &ExtensionValue) -> Result<Expr, Self::Error> {
585 match value {
586 ExtensionValue::Expr(e) => Ok(e.clone()),
587 ExtensionValue::Integer(i) => Ok(Expr::from(*i)),
594 ExtensionValue::Float(f) => Ok(Expr::from(*f)),
595 ExtensionValue::String(s) => Ok(Expr::from(s.as_str())),
596 ExtensionValue::Boolean(b) => Ok(Expr::from(*b)),
597 v => Err(invalid_type(ExtensionValueKind::Expression, v)),
598 }
599 }
600}
601
602#[derive(Debug, Clone)]
608pub enum ExtensionColumn {
609 Named {
611 name: String,
613 r#type: proto::Type,
617 },
618 Expr(Expr),
620}
621
622impl ExtensionColumn {
623 pub fn field(index: i32) -> Self {
625 Self::Expr(Expr::field(index))
626 }
627}
628
629impl ExtensionArgs {
630 pub fn push<T>(&mut self, value: T)
632 where
633 T: Into<ExtensionValue>,
634 {
635 self.positional.push(value.into());
636 }
637
638 pub fn insert<K, V>(&mut self, name: K, value: V) -> Option<ExtensionValue>
640 where
641 K: Into<String>,
642 V: Into<ExtensionValue>,
643 {
644 self.named.insert(name.into(), value.into())
645 }
646
647 pub fn extractor(&self) -> ArgsExtractor<'_> {
649 ArgsExtractor::new(self)
650 }
651}