nu_command/math/
abs.rs

1use crate::math::utils::ensure_bounded;
2use nu_engine::command_prelude::*;
3
4#[derive(Clone)]
5pub struct MathAbs;
6
7impl Command for MathAbs {
8    fn name(&self) -> &str {
9        "math abs"
10    }
11
12    fn signature(&self) -> Signature {
13        Signature::build("math abs")
14            .input_output_types(vec![
15                (Type::Number, Type::Number),
16                (Type::Duration, Type::Duration),
17                (
18                    Type::List(Box::new(Type::Number)),
19                    Type::List(Box::new(Type::Number)),
20                ),
21                (
22                    Type::List(Box::new(Type::Duration)),
23                    Type::List(Box::new(Type::Duration)),
24                ),
25                (Type::Range, Type::List(Box::new(Type::Number))),
26            ])
27            .allow_variants_without_examples(true)
28            .category(Category::Math)
29    }
30
31    fn description(&self) -> &str {
32        "Returns the absolute value of a number."
33    }
34
35    fn search_terms(&self) -> Vec<&str> {
36        vec!["absolute", "modulus", "positive", "distance"]
37    }
38
39    fn is_const(&self) -> bool {
40        true
41    }
42
43    fn run(
44        &self,
45        engine_state: &EngineState,
46        _stack: &mut Stack,
47        call: &Call,
48        input: PipelineData,
49    ) -> Result<PipelineData, ShellError> {
50        let head = call.head;
51        if let PipelineData::Value(ref v @ Value::Range { ref val, .. }, ..) = input {
52            let span = v.span();
53            ensure_bounded(val, span, head)?;
54        }
55        input.map(move |value| abs_helper(value, head), engine_state.signals())
56    }
57
58    fn run_const(
59        &self,
60        working_set: &StateWorkingSet,
61        call: &Call,
62        input: PipelineData,
63    ) -> Result<PipelineData, ShellError> {
64        let head = call.head;
65        if let PipelineData::Value(ref v @ Value::Range { ref val, .. }, ..) = input {
66            let span = v.span();
67            ensure_bounded(val, span, head)?;
68        }
69        input.map(
70            move |value| abs_helper(value, head),
71            working_set.permanent().signals(),
72        )
73    }
74
75    fn examples(&self) -> Vec<Example<'_>> {
76        vec![Example {
77            description: "Compute absolute value of each number in a list of numbers",
78            example: "[-50 -100.0 25] | math abs",
79            result: Some(Value::list(
80                vec![
81                    Value::test_int(50),
82                    Value::test_float(100.0),
83                    Value::test_int(25),
84                ],
85                Span::test_data(),
86            )),
87        }]
88    }
89}
90
91fn abs_helper(val: Value, head: Span) -> Value {
92    let span = val.span();
93    match val {
94        Value::Int { val, .. } => Value::int(val.abs(), span),
95        Value::Float { val, .. } => Value::float(val.abs(), span),
96        Value::Duration { val, .. } => Value::duration(val.abs(), span),
97        Value::Error { .. } => val,
98        other => Value::error(
99            ShellError::OnlySupportsThisInputType {
100                exp_input_type: "numeric".into(),
101                wrong_type: other.get_type().to_string(),
102                dst_span: head,
103                src_span: other.span(),
104            },
105            head,
106        ),
107    }
108}
109
110#[cfg(test)]
111mod test {
112    use super::*;
113
114    #[test]
115    fn test_examples() {
116        use crate::test_examples;
117
118        test_examples(MathAbs {})
119    }
120}