vrl/stdlib/
is_empty.rs

1use crate::compiler::prelude::*;
2
3fn is_empty(value: Value) -> Resolved {
4    let empty = match value {
5        Value::Object(v) => v.is_empty(),
6        Value::Array(v) => v.is_empty(),
7        Value::Bytes(v) => v.is_empty(),
8        value => {
9            return Err(ValueError::Expected {
10                got: value.kind(),
11                expected: Kind::array(Collection::any())
12                    | Kind::object(Collection::any())
13                    | Kind::bytes(),
14            }
15            .into());
16        }
17    };
18
19    Ok(empty.into())
20}
21
22#[derive(Clone, Copy, Debug)]
23pub struct IsEmpty;
24
25impl Function for IsEmpty {
26    fn identifier(&self) -> &'static str {
27        "is_empty"
28    }
29
30    fn usage(&self) -> &'static str {
31        "Check if the object, array, or string has a length of `0`."
32    }
33
34    fn category(&self) -> &'static str {
35        Category::Type.as_ref()
36    }
37
38    fn return_kind(&self) -> u16 {
39        kind::BOOLEAN
40    }
41
42    fn return_rules(&self) -> &'static [&'static str] {
43        &[
44            "Returns `true` if `value` is empty.",
45            "Returns `false` if `value` is non-empty.",
46        ]
47    }
48
49    fn parameters(&self) -> &'static [Parameter] {
50        const PARAMETERS: &[Parameter] = &[Parameter::required(
51            "value",
52            kind::OBJECT | kind::ARRAY | kind::BYTES,
53            "The value to check.",
54        )];
55        PARAMETERS
56    }
57
58    fn examples(&self) -> &'static [Example] {
59        &[
60            example! {
61                title: "Empty array",
62                source: "is_empty([])",
63                result: Ok("true"),
64            },
65            example! {
66                title: "Non-empty string",
67                source: r#"is_empty("a string")"#,
68                result: Ok("false"),
69            },
70            example! {
71                title: "Non-empty object",
72                source: r#"is_empty({"foo": "bar"})"#,
73                result: Ok("false"),
74            },
75            example! {
76                title: "Empty string",
77                source: r#"is_empty("")"#,
78                result: Ok("true"),
79            },
80            example! {
81                title: "Empty object",
82                source: "is_empty({})",
83                result: Ok("true"),
84            },
85            example! {
86                title: "Non-empty array",
87                source: "is_empty([1,2,3])",
88                result: Ok("false"),
89            },
90        ]
91    }
92
93    fn compile(
94        &self,
95        _state: &state::TypeState,
96        _ctx: &mut FunctionCompileContext,
97        arguments: ArgumentList,
98    ) -> Compiled {
99        let value = arguments.required("value");
100
101        Ok(IsEmptyFn { value }.as_expr())
102    }
103}
104
105#[derive(Debug, Clone)]
106struct IsEmptyFn {
107    value: Box<dyn Expression>,
108}
109
110impl FunctionExpression for IsEmptyFn {
111    fn resolve(&self, ctx: &mut Context) -> Resolved {
112        let value = self.value.resolve(ctx)?;
113        is_empty(value)
114    }
115
116    fn type_def(&self, _: &state::TypeState) -> TypeDef {
117        TypeDef::boolean().infallible()
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124    use crate::value;
125
126    test_function![
127        is_empty => IsEmpty;
128
129        empty_array {
130            args: func_args![value: value!([])],
131            want: Ok(value!(true)),
132            tdef: TypeDef::boolean().infallible(),
133        }
134
135        non_empty_array {
136            args: func_args![value: value!(["foo"])],
137            want: Ok(value!(false)),
138            tdef: TypeDef::boolean().infallible(),
139        }
140
141        empty_object {
142            args: func_args![value: value!({})],
143            want: Ok(value!(true)),
144            tdef: TypeDef::boolean().infallible(),
145        }
146
147        non_empty_object {
148            args: func_args![value: value!({"foo": "bar"})],
149            want: Ok(value!(false)),
150            tdef: TypeDef::boolean().infallible(),
151        }
152
153        empty_string {
154            args: func_args![value: ""],
155            want: Ok(value!(true)),
156            tdef: TypeDef::boolean().infallible(),
157        }
158
159        non_empty_string {
160            args: func_args![value: "foo"],
161            want: Ok(value!(false)),
162            tdef: TypeDef::boolean().infallible(),
163        }
164    ];
165}