vrl/stdlib/
decode_percent.rs1use crate::compiler::prelude::*;
2use percent_encoding::percent_decode;
3
4fn decode_percent(value: Value) -> Resolved {
5 let value = value.try_bytes()?;
6 Ok(percent_decode(&value)
7 .decode_utf8_lossy()
8 .to_string()
9 .into())
10}
11
12#[derive(Clone, Copy, Debug)]
13pub struct DecodePercent;
14
15impl Function for DecodePercent {
16 fn identifier(&self) -> &'static str {
17 "decode_percent"
18 }
19
20 fn usage(&self) -> &'static str {
21 "Decodes a [percent-encoded](https://url.spec.whatwg.org/#percent-encoded-bytes) `value` like a URL."
22 }
23
24 fn category(&self) -> &'static str {
25 Category::Codec.as_ref()
26 }
27
28 fn return_kind(&self) -> u16 {
29 kind::BYTES
30 }
31
32 fn parameters(&self) -> &'static [Parameter] {
33 const PARAMETERS: &[Parameter] = &[Parameter::required(
34 "value",
35 kind::BYTES,
36 "The string to decode.",
37 )];
38 PARAMETERS
39 }
40
41 fn compile(
42 &self,
43 _state: &state::TypeState,
44 _ctx: &mut FunctionCompileContext,
45 arguments: ArgumentList,
46 ) -> Compiled {
47 let value = arguments.required("value");
48
49 Ok(DecodePercentFn { value }.as_expr())
50 }
51
52 fn examples(&self) -> &'static [Example] {
53 &[example! {
54 title: "Percent decode a value",
55 source: r#"decode_percent("foo%20bar%3F")"#,
56 result: Ok("foo bar?"),
57 }]
58 }
59}
60
61#[derive(Clone, Debug)]
62struct DecodePercentFn {
63 value: Box<dyn Expression>,
64}
65
66impl FunctionExpression for DecodePercentFn {
67 fn resolve(&self, ctx: &mut Context) -> Resolved {
68 let value = self.value.resolve(ctx)?;
69
70 decode_percent(value)
71 }
72
73 fn type_def(&self, _: &state::TypeState) -> TypeDef {
74 TypeDef::bytes().infallible()
75 }
76}
77
78#[cfg(test)]
79mod test {
80 use super::*;
81 use crate::value;
82
83 test_function![
84 decode_percent => DecodePercent;
85
86 decode {
87 args: func_args![value: value!("foo%20%23%22%3C%3E%3F%60%7B%7D%2F%3A%3B%3D%40%5B%5C%5D%5E%7C%24%25%26%2B%2C%21%27%28%29%7Ebar")],
88 want: Ok(value!(r#"foo #"<>?`{}/:;=@[\]^|$%&+,!'()~bar"#)),
89 tdef: TypeDef::bytes().infallible(),
90 }
91 ];
92}