1use std::env::VarError;
5use std::sync::LazyLock;
6
7use vortex_dtype::DType;
8use vortex_error::VortexResult;
9use vortex_error::vortex_bail;
10use vortex_error::vortex_panic;
11
12use crate::AnyCanonical;
13use crate::Array;
14use crate::ArrayRef;
15use crate::Canonical;
16use crate::CanonicalView;
17use crate::Executable;
18use crate::ExecutionCtx;
19use crate::IntoArray;
20use crate::arrays::ConstantArray;
21use crate::arrays::ConstantVTable;
22use crate::matcher::Matcher;
23use crate::scalar::Scalar;
24
25pub enum Columnar {
31 Canonical(Canonical),
33 Constant(ConstantArray),
35}
36
37impl Columnar {
38 pub fn constant<S: Into<Scalar>>(scalar: S, len: usize) -> Self {
40 Columnar::Constant(ConstantArray::new(scalar.into(), len))
41 }
42
43 pub fn len(&self) -> usize {
45 match self {
46 Columnar::Canonical(canonical) => canonical.len(),
47 Columnar::Constant(constant) => constant.len(),
48 }
49 }
50
51 pub fn is_empty(&self) -> bool {
53 self.len() == 0
54 }
55
56 pub fn dtype(&self) -> &DType {
58 match self {
59 Columnar::Canonical(canonical) => canonical.dtype(),
60 Columnar::Constant(constant) => constant.dtype(),
61 }
62 }
63}
64
65impl IntoArray for Columnar {
66 fn into_array(self) -> ArrayRef {
67 match self {
68 Columnar::Canonical(canonical) => canonical.into_array(),
69 Columnar::Constant(constant) => constant.into_array(),
70 }
71 }
72}
73
74impl Executable for Columnar {
81 fn execute(mut array: ArrayRef, ctx: &mut ExecutionCtx) -> VortexResult<Self> {
82 static MAX_ITERATIONS: LazyLock<usize> =
83 LazyLock::new(|| match std::env::var("VORTEX_MAX_ITERATIONS") {
84 Ok(val) => val.parse::<usize>().unwrap_or_else(|e| {
85 vortex_panic!("VORTEX_MAX_ITERATIONS is not a valid usize: {e}")
86 }),
87 Err(VarError::NotPresent) => 128,
88 Err(VarError::NotUnicode(_)) => {
89 vortex_panic!("VORTEX_MAX_ITERATIONS is not a valid unicode string")
90 }
91 });
92
93 for _ in 0..*MAX_ITERATIONS {
94 if let Some(constant) = array.as_opt::<ConstantVTable>() {
96 ctx.log(format_args!("-> constant({})", constant.scalar()));
97 return Ok(Columnar::Constant(constant.clone()));
98 }
99 if let Some(canonical) = array.as_opt::<AnyCanonical>() {
100 ctx.log(format_args!("-> canonical {}", array));
101 return Ok(Columnar::Canonical(canonical.into()));
102 }
103
104 array = array.execute(ctx)?;
106 }
107
108 vortex_bail!("Exceeded maximum execution iterations while executing to Columnar")
110 }
111}
112
113pub enum ColumnarView<'a> {
114 Canonical(CanonicalView<'a>),
115 Constant(&'a ConstantArray),
116}
117
118impl<'a> AsRef<dyn Array> for ColumnarView<'a> {
119 fn as_ref(&self) -> &dyn Array {
120 match self {
121 ColumnarView::Canonical(canonical) => canonical.as_ref(),
122 ColumnarView::Constant(constant) => constant.as_ref(),
123 }
124 }
125}
126
127pub struct AnyColumnar;
128impl Matcher for AnyColumnar {
129 type Match<'a> = ColumnarView<'a>;
130
131 fn try_match<'a>(array: &'a dyn Array) -> Option<Self::Match<'a>> {
132 if let Some(constant) = array.as_opt::<ConstantVTable>() {
133 Some(ColumnarView::Constant(constant))
134 } else {
135 array.as_opt::<AnyCanonical>().map(ColumnarView::Canonical)
136 }
137 }
138}