vrl/stdlib/
abs.rs

1use crate::compiler::prelude::*;
2
3fn abs(value: Value) -> Resolved {
4    match value {
5        Value::Float(f) => Ok(Value::from_f64_or_zero(f.abs())),
6        Value::Integer(i) => Ok(Value::from(i.abs())),
7        value => Err(ValueError::Expected {
8            got: value.kind(),
9            expected: Kind::float() | Kind::integer(),
10        }
11        .into()),
12    }
13}
14
15#[derive(Clone, Copy, Debug)]
16pub struct Abs;
17
18impl Function for Abs {
19    fn identifier(&self) -> &'static str {
20        "abs"
21    }
22
23    fn usage(&self) -> &'static str {
24        "Computes the absolute value of `value`."
25    }
26
27    fn category(&self) -> &'static str {
28        Category::Number.as_ref()
29    }
30
31    fn return_kind(&self) -> u16 {
32        kind::INTEGER | kind::FLOAT
33    }
34
35    fn return_rules(&self) -> &'static [&'static str] {
36        &["Returns the absolute value."]
37    }
38
39    fn parameters(&self) -> &'static [Parameter] {
40        const PARAMETERS: &[Parameter] = &[Parameter::required(
41            "value",
42            kind::FLOAT | kind::INTEGER,
43            "The number to calculate the absolute value.",
44        )];
45        PARAMETERS
46    }
47
48    fn compile(
49        &self,
50        _state: &state::TypeState,
51        _ctx: &mut FunctionCompileContext,
52        arguments: ArgumentList,
53    ) -> Compiled {
54        let value = arguments.required("value");
55
56        Ok(AbsFn { value }.as_expr())
57    }
58
59    fn examples(&self) -> &'static [Example] {
60        &[
61            example! {
62                title: "Computes the absolute value of an integer",
63                source: "abs(-42)",
64                result: Ok("42"),
65            },
66            example! {
67                title: "Computes the absolute value of a float",
68                source: "abs(-42.2)",
69                result: Ok("42.2"),
70            },
71            example! {
72                title: "Computes the absolute value of a positive integer",
73                source: "abs(10)",
74                result: Ok("10"),
75            },
76        ]
77    }
78}
79
80#[derive(Clone, Debug)]
81struct AbsFn {
82    value: Box<dyn Expression>,
83}
84
85impl FunctionExpression for AbsFn {
86    fn resolve(&self, ctx: &mut Context) -> Resolved {
87        let value = self.value.resolve(ctx)?;
88
89        abs(value)
90    }
91
92    fn type_def(&self, state: &state::TypeState) -> TypeDef {
93        match Kind::from(self.value.type_def(state)) {
94            v if v.is_float() || v.is_integer() => v.into(),
95            _ => Kind::integer().or_float().into(),
96        }
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103    use crate::value;
104
105    test_function![
106        abs => Abs;
107
108        integer_negative {
109            args: func_args![value: value!(-42)],
110            want: Ok(value!(42)),
111            tdef: TypeDef::integer(),
112        }
113
114        integer_positive {
115            args: func_args![value: value!(42)],
116            want: Ok(value!(42)),
117            tdef: TypeDef::integer(),
118        }
119
120        float_negative {
121            args: func_args![value: value!(-42.2)],
122            want: Ok(value!(42.2)),
123            tdef: TypeDef::float(),
124        }
125
126        float_positive {
127            args: func_args![value: value!(42.2)],
128            want: Ok(value!(42.2)),
129            tdef: TypeDef::float(),
130        }
131    ];
132}