use crate::compiler::prelude::*;
fn abs(value: Value) -> Resolved {
match value {
Value::Float(f) => Ok(Value::from_f64_or_zero(f.abs())),
Value::Integer(i) => Ok(Value::from(i.abs())),
value => Err(ValueError::Expected {
got: value.kind(),
expected: Kind::float() | Kind::integer(),
}
.into()),
}
}
#[derive(Clone, Copy, Debug)]
pub struct Abs;
impl Function for Abs {
fn identifier(&self) -> &'static str {
"abs"
}
fn usage(&self) -> &'static str {
"Computes the absolute value of `value`."
}
fn category(&self) -> &'static str {
Category::Number.as_ref()
}
fn return_kind(&self) -> u16 {
kind::INTEGER | kind::FLOAT
}
fn return_rules(&self) -> &'static [&'static str] {
&["Returns the absolute value."]
}
fn parameters(&self) -> &'static [Parameter] {
const PARAMETERS: &[Parameter] = &[Parameter::required(
"value",
kind::FLOAT | kind::INTEGER,
"The number to calculate the absolute value.",
)];
PARAMETERS
}
fn compile(
&self,
_state: &state::TypeState,
_ctx: &mut FunctionCompileContext,
arguments: ArgumentList,
) -> Compiled {
let value = arguments.required("value");
Ok(AbsFn { value }.as_expr())
}
fn examples(&self) -> &'static [Example] {
&[
example! {
title: "Computes the absolute value of an integer",
source: "abs(-42)",
result: Ok("42"),
},
example! {
title: "Computes the absolute value of a float",
source: "abs(-42.2)",
result: Ok("42.2"),
},
example! {
title: "Computes the absolute value of a positive integer",
source: "abs(10)",
result: Ok("10"),
},
]
}
}
#[derive(Clone, Debug)]
struct AbsFn {
value: Box<dyn Expression>,
}
impl FunctionExpression for AbsFn {
fn resolve(&self, ctx: &mut Context) -> Resolved {
let value = self.value.resolve(ctx)?;
abs(value)
}
fn type_def(&self, state: &state::TypeState) -> TypeDef {
match Kind::from(self.value.type_def(state)) {
v if v.is_float() || v.is_integer() => v.into(),
_ => Kind::integer().or_float().into(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::value;
test_function![
abs => Abs;
integer_negative {
args: func_args![value: value!(-42)],
want: Ok(value!(42)),
tdef: TypeDef::integer(),
}
integer_positive {
args: func_args![value: value!(42)],
want: Ok(value!(42)),
tdef: TypeDef::integer(),
}
float_negative {
args: func_args![value: value!(-42.2)],
want: Ok(value!(42.2)),
tdef: TypeDef::float(),
}
float_positive {
args: func_args![value: value!(42.2)],
want: Ok(value!(42.2)),
tdef: TypeDef::float(),
}
];
}