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}