vrl/stdlib/
unique.rs

1use crate::compiler::prelude::*;
2use indexmap::IndexSet;
3
4fn unique(value: Value) -> Resolved {
5    let value = value.try_array()?;
6    let set: IndexSet<_> = value.into_iter().collect();
7    Ok(set.into_iter().collect())
8}
9
10#[derive(Clone, Copy, Debug)]
11pub struct Unique;
12
13impl Function for Unique {
14    fn identifier(&self) -> &'static str {
15        "unique"
16    }
17
18    fn usage(&self) -> &'static str {
19        indoc! {"
20            Returns the unique values for an array.
21
22            The first occurrence of each element is kept.
23        "}
24    }
25
26    fn category(&self) -> &'static str {
27        Category::Enumerate.as_ref()
28    }
29
30    fn return_kind(&self) -> u16 {
31        kind::ARRAY
32    }
33
34    fn examples(&self) -> &'static [Example] {
35        &[example! {
36            title: "Unique",
37            source: r#"unique(["foo", "bar", "foo", "baz"])"#,
38            result: Ok(r#"["foo", "bar", "baz"]"#),
39        }]
40    }
41
42    fn compile(
43        &self,
44        _state: &state::TypeState,
45        _ctx: &mut FunctionCompileContext,
46        arguments: ArgumentList,
47    ) -> Compiled {
48        let value = arguments.required("value");
49
50        Ok(UniqueFn { value }.as_expr())
51    }
52
53    fn parameters(&self) -> &'static [Parameter] {
54        const PARAMETERS: &[Parameter] = &[Parameter::required(
55            "value",
56            kind::ARRAY,
57            "The array to return unique elements from.",
58        )];
59        PARAMETERS
60    }
61}
62
63#[derive(Debug, Clone)]
64pub(crate) struct UniqueFn {
65    value: Box<dyn Expression>,
66}
67
68impl FunctionExpression for UniqueFn {
69    fn resolve(&self, ctx: &mut Context) -> Resolved {
70        let value = self.value.resolve(ctx)?;
71        unique(value)
72    }
73
74    fn type_def(&self, _: &state::TypeState) -> TypeDef {
75        TypeDef::array(Collection::any())
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82    use crate::value;
83
84    test_function![
85        unique => Unique;
86
87        default {
88            args: func_args![
89                value: value!(["bar", "foo", "baz", "foo"]),
90            ],
91            want: Ok(value!(["bar", "foo", "baz"])),
92            tdef: TypeDef::array(Collection::any()),
93        }
94
95        mixed_values {
96            args: func_args![
97                value: value!(["foo", [1,2,3], "123abc", 1, true, [1,2,3], "foo", true, 1]),
98            ],
99            want: Ok(value!(["foo", [1,2,3], "123abc", 1, true])),
100            tdef: TypeDef::array(Collection::any()),
101        }
102    ];
103}