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}