vrl/compiler/expression/
array.rs1use 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 fallible |= type_def.is_fallible();
60
61 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}