vrl/stdlib/
strip_whitespace.rs

1use crate::compiler::prelude::*;
2
3#[derive(Clone, Copy, Debug)]
4pub struct StripWhitespace;
5
6impl Function for StripWhitespace {
7    fn identifier(&self) -> &'static str {
8        "strip_whitespace"
9    }
10
11    fn usage(&self) -> &'static str {
12        "Strips whitespace from the start and end of `value`, where whitespace is defined by the [Unicode `White_Space` property](https://en.wikipedia.org/wiki/Unicode_character_property#Whitespace)."
13    }
14
15    fn category(&self) -> &'static str {
16        Category::String.as_ref()
17    }
18
19    fn return_kind(&self) -> u16 {
20        kind::BYTES
21    }
22
23    fn parameters(&self) -> &'static [Parameter] {
24        const PARAMETERS: &[Parameter] = &[Parameter::required(
25            "value",
26            kind::BYTES,
27            "The string to trim.",
28        )];
29        PARAMETERS
30    }
31
32    fn examples(&self) -> &'static [Example] {
33        &[
34            example! {
35                title: "Strip whitespace",
36                source: r#"strip_whitespace("  A sentence.  ")"#,
37                result: Ok("A sentence."),
38            },
39            example! {
40                title: "Start whitespace",
41                source: r#"strip_whitespace("  foobar")"#,
42                result: Ok("foobar"),
43            },
44            example! {
45                title: "End whitespace",
46                source: r#"strip_whitespace("foo bar  ")"#,
47                result: Ok("foo bar"),
48            },
49            example! {
50                title: "Newlines",
51                source: r#"strip_whitespace("\n\nfoo bar\n  ")"#,
52                result: Ok("foo bar"),
53            },
54        ]
55    }
56
57    fn compile(
58        &self,
59        _state: &state::TypeState,
60        _ctx: &mut FunctionCompileContext,
61        arguments: ArgumentList,
62    ) -> Compiled {
63        let value = arguments.required("value");
64
65        Ok(StripWhitespaceFn { value }.as_expr())
66    }
67}
68
69#[derive(Debug, Clone)]
70struct StripWhitespaceFn {
71    value: Box<dyn Expression>,
72}
73
74impl FunctionExpression for StripWhitespaceFn {
75    fn resolve(&self, ctx: &mut Context) -> Resolved {
76        let value = self.value.resolve(ctx)?;
77
78        Ok(value.try_bytes_utf8_lossy()?.trim().into())
79    }
80
81    fn type_def(&self, _: &state::TypeState) -> TypeDef {
82        TypeDef::bytes().infallible()
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    test_function![
91        strip_whitespace => StripWhitespace;
92
93        empty {
94            args: func_args![value: ""],
95            want: Ok(""),
96            tdef: TypeDef::bytes().infallible(),
97        }
98
99        just_spaces {
100            args: func_args![value: "      "],
101            want: Ok(""),
102            tdef: TypeDef::bytes().infallible(),
103        }
104
105        no_spaces {
106            args: func_args![value: "hi there"],
107            want: Ok("hi there"),
108            tdef: TypeDef::bytes().infallible(),
109        }
110
111        spaces {
112            args: func_args![value: "           hi there        "],
113            want: Ok("hi there"),
114            tdef: TypeDef::bytes().infallible(),
115        }
116
117        unicode_whitespace {
118            args: func_args![value: " \u{3000}\u{205F}\u{202F}\u{A0}\u{9} ❤❤ hi there ❤❤  \u{9}\u{A0}\u{202F}\u{205F}\u{3000} "],
119            want: Ok("❤❤ hi there ❤❤"),
120            tdef: TypeDef::bytes().infallible(),
121        }
122    ];
123}