vrl/stdlib/
tally_value.rs1use crate::compiler::prelude::*;
2
3fn tally_value(array: Value, value: &Value) -> Resolved {
4 let array = array.try_array()?;
5 Ok(array.iter().filter(|&v| v == value).count().into())
6}
7
8#[derive(Clone, Copy, Debug)]
9pub struct TallyValue;
10
11impl Function for TallyValue {
12 fn identifier(&self) -> &'static str {
13 "tally_value"
14 }
15
16 fn usage(&self) -> &'static str {
17 "Counts the number of times a specific value appears in the provided array."
18 }
19
20 fn category(&self) -> &'static str {
21 Category::Enumerate.as_ref()
22 }
23
24 fn return_kind(&self) -> u16 {
25 kind::INTEGER
26 }
27
28 fn examples(&self) -> &'static [Example] {
29 &[example! {
30 title: "count matching values",
31 source: r#"tally_value(["foo", "bar", "foo", "baz"], "foo")"#,
32 result: Ok("2"),
33 }]
34 }
35
36 fn compile(
37 &self,
38 _state: &state::TypeState,
39 _ctx: &mut FunctionCompileContext,
40 arguments: ArgumentList,
41 ) -> Compiled {
42 let array = arguments.required("array");
43 let value = arguments.required("value");
44
45 Ok(TallyValueFn { array, value }.as_expr())
46 }
47
48 fn parameters(&self) -> &'static [Parameter] {
49 const PARAMETERS: &[Parameter] = &[
50 Parameter::required("array", kind::ARRAY, "The array to search through."),
51 Parameter::required(
52 "value",
53 kind::ANY,
54 "The value to count occurrences of in the array.",
55 ),
56 ];
57 PARAMETERS
58 }
59}
60
61#[derive(Debug, Clone)]
62pub(crate) struct TallyValueFn {
63 array: Box<dyn Expression>,
64 value: Box<dyn Expression>,
65}
66
67impl FunctionExpression for TallyValueFn {
68 fn resolve(&self, ctx: &mut Context) -> Resolved {
69 let array = self.array.resolve(ctx)?;
70 let value = self.value.resolve(ctx)?;
71
72 tally_value(array, &value)
73 }
74
75 fn type_def(&self, _: &state::TypeState) -> TypeDef {
76 TypeDef::integer().infallible()
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 use crate::value;
84
85 test_function![
86 tally_value => TallyValue;
87
88 default {
89 args: func_args![
90 array: value!(["bar", "foo", "baz", "foo"]),
91 value: value!("foo"),
92 ],
93 want: Ok(value!(2)),
94 tdef: TypeDef::integer().infallible(),
95 }
96 ];
97}