vrl/stdlib/
strlen.rs

1use crate::compiler::prelude::*;
2
3fn strlen(value: &Value) -> Resolved {
4    let v = value.try_bytes_utf8_lossy()?;
5
6    Ok(v.chars().count().into())
7}
8
9#[derive(Clone, Copy, Debug)]
10pub struct Strlen;
11
12impl Function for Strlen {
13    fn identifier(&self) -> &'static str {
14        "strlen"
15    }
16
17    fn usage(&self) -> &'static str {
18        indoc! {"
19            Returns the number of UTF-8 characters in `value`. This differs from
20            `length` which counts the number of bytes of a string.
21
22            **Note**: This is the count of [Unicode scalar values](https://www.unicode.org/glossary/#unicode_scalar_value)
23            which can sometimes differ from [Unicode code points](https://www.unicode.org/glossary/#code_point).
24        "}
25    }
26
27    fn category(&self) -> &'static str {
28        Category::Enumerate.as_ref()
29    }
30
31    fn return_kind(&self) -> u16 {
32        kind::INTEGER
33    }
34
35    fn parameters(&self) -> &'static [Parameter] {
36        const PARAMETERS: &[Parameter] =
37            &[Parameter::required("value", kind::BYTES, "The string.")];
38        PARAMETERS
39    }
40
41    fn examples(&self) -> &'static [Example] {
42        &[example! {
43            title: "Count Unicode scalar values",
44            source: r#"strlen("ñandú")"#,
45            result: Ok("5"),
46        }]
47    }
48
49    fn compile(
50        &self,
51        _state: &state::TypeState,
52        _ctx: &mut FunctionCompileContext,
53        arguments: ArgumentList,
54    ) -> Compiled {
55        let value = arguments.required("value");
56
57        Ok(StrlenFn { value }.as_expr())
58    }
59}
60
61#[derive(Debug, Clone)]
62struct StrlenFn {
63    value: Box<dyn Expression>,
64}
65
66impl FunctionExpression for StrlenFn {
67    fn resolve(&self, ctx: &mut Context) -> Resolved {
68        let value = self.value.resolve(ctx)?;
69
70        strlen(&value)
71    }
72
73    fn type_def(&self, _state: &state::TypeState) -> TypeDef {
74        TypeDef::integer().infallible()
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81    use crate::value;
82
83    test_function![
84        strlen => Strlen;
85
86        string_value {
87            args: func_args![value: value!("ñandú")],
88            want: Ok(value!(5)),
89            tdef: TypeDef::integer().infallible(),
90        }
91    ];
92}