vrl/compiler/expression/
array.rs

1use std::{collections::BTreeMap, fmt, ops::Deref};
2
3use crate::value::Value;
4use crate::{
5    compiler::{
6        Context, Expression, TypeDef,
7        expression::{Expr, Resolved},
8        state::{TypeInfo, TypeState},
9    },
10    value::Kind,
11};
12
13#[derive(Debug, Clone, PartialEq)]
14pub struct Array {
15    inner: Vec<Expr>,
16}
17
18impl Array {
19    pub(crate) fn new(inner: Vec<Expr>) -> Self {
20        Self { inner }
21    }
22}
23
24impl Deref for Array {
25    type Target = Vec<Expr>;
26
27    fn deref(&self) -> &Self::Target {
28        &self.inner
29    }
30}
31
32impl Expression for Array {
33    fn resolve(&self, ctx: &mut Context) -> Resolved {
34        self.inner
35            .iter()
36            .map(|expr| expr.resolve(ctx))
37            .collect::<Result<Vec<_>, _>>()
38            .map(Value::Array)
39    }
40
41    fn resolve_constant(&self, state: &TypeState) -> Option<Value> {
42        self.inner
43            .iter()
44            .map(|x| x.resolve_constant(state))
45            .collect::<Option<Vec<_>>>()
46            .map(Value::Array)
47    }
48
49    fn type_info(&self, state: &TypeState) -> TypeInfo {
50        let mut state = state.clone();
51
52        let mut type_defs = vec![];
53        let mut fallible = false;
54
55        for expr in &self.inner {
56            let type_def = expr.apply_type_info(&mut state).upgrade_undefined();
57
58            // If any expression is fallible, the entire array is fallible.
59            fallible |= type_def.is_fallible();
60
61            // If any expression aborts, the entire array aborts
62            if type_def.is_never() {
63                return TypeInfo::new(state, TypeDef::never().maybe_fallible(fallible));
64            }
65            type_defs.push(type_def);
66        }
67
68        let returns = type_defs.iter().fold(Kind::never(), |returns, type_def| {
69            returns.union(type_def.returns().clone())
70        });
71
72        let collection = type_defs
73            .into_iter()
74            .enumerate()
75            .map(|(index, type_def)| (index.into(), type_def.into()))
76            .collect::<BTreeMap<_, _>>();
77
78        TypeInfo::new(
79            state,
80            TypeDef::array(collection)
81                .maybe_fallible(fallible)
82                .with_returns(returns),
83        )
84    }
85}
86
87impl fmt::Display for Array {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        let exprs = self
90            .inner
91            .iter()
92            .map(Expr::to_string)
93            .collect::<Vec<_>>()
94            .join(", ");
95
96        write!(f, "[{exprs}]")
97    }
98}
99
100impl From<Vec<Expr>> for Array {
101    fn from(inner: Vec<Expr>) -> Self {
102        Self { inner }
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use crate::value::kind::Collection;
109    use crate::{expr, test_type_def, value::Kind};
110
111    use super::*;
112
113    test_type_def![
114        empty_array {
115            expr: |_| expr!([]),
116            want: TypeDef::array(Collection::empty()),
117        }
118
119        scalar_array {
120            expr: |_| expr!([1, "foo", true]),
121            want: TypeDef::array(BTreeMap::from([
122                (0.into(), Kind::integer()),
123                (1.into(), Kind::bytes()),
124                (2.into(), Kind::boolean()),
125            ])),
126        }
127
128        mixed_array {
129            expr: |_| expr!([1, [true, "foo"], { "bar": null }]),
130            want: TypeDef::array(BTreeMap::from([
131                (0.into(), Kind::integer()),
132                (1.into(), Kind::array(BTreeMap::from([
133                    (0.into(), Kind::boolean()),
134                    (1.into(), Kind::bytes()),
135                ]))),
136                (2.into(), Kind::object(BTreeMap::from([
137                    ("bar".into(), Kind::null())
138                ]))),
139            ])),
140        }
141    ];
142}