Skip to main content

nu_cmd_extra/extra/bits/
xor.rs

1use super::binary_op;
2use nu_engine::command_prelude::*;
3use nu_heavy_utils::Endian;
4
5#[derive(Clone)]
6pub struct BitsXor;
7
8impl Command for BitsXor {
9    fn name(&self) -> &str {
10        "bits xor"
11    }
12
13    fn signature(&self) -> Signature {
14        Signature::build("bits xor")
15            .input_output_types(vec![
16                (Type::Int, Type::Int),
17                (Type::Binary, Type::Binary),
18                (
19                    Type::List(Box::new(Type::Int)),
20                    Type::List(Box::new(Type::Int)),
21                ),
22                (
23                    Type::List(Box::new(Type::Binary)),
24                    Type::List(Box::new(Type::Binary)),
25                ),
26            ])
27            .allow_variants_without_examples(true)
28            .required(
29                "target",
30                SyntaxShape::OneOf(vec![SyntaxShape::Binary, SyntaxShape::Int]),
31                "Right-hand side of the operation.",
32            )
33            .param(Endian::flag())
34            .category(Category::Bits)
35    }
36
37    fn description(&self) -> &str {
38        "Performs bitwise xor for ints or binary values."
39    }
40
41    fn search_terms(&self) -> Vec<&str> {
42        vec!["logic xor"]
43    }
44
45    fn run(
46        &self,
47        engine_state: &EngineState,
48        stack: &mut Stack,
49        call: &Call,
50        input: PipelineData,
51    ) -> Result<PipelineData, ShellError> {
52        let head = call.head;
53        let target: Value = call.req(engine_state, stack, 0)?;
54        let endian = call
55            .get_flag::<Endian>(engine_state, stack, "endian")?
56            .unwrap_or_default();
57
58        // This doesn't match explicit nulls
59        if let PipelineData::Empty = input {
60            return Err(ShellError::PipelineEmpty { dst_span: head });
61        }
62
63        input.map(
64            move |value| binary_op(&value, &target, endian, |(l, r)| l ^ r, head),
65            engine_state.signals(),
66        )
67    }
68
69    fn examples(&self) -> Vec<Example<'_>> {
70        vec![
71            Example {
72                description: "Apply bits xor to two numbers",
73                example: "2 | bits xor 2",
74                result: Some(Value::test_int(0)),
75            },
76            Example {
77                description: "Apply bitwise xor to a list of numbers",
78                example: "[8 3 2] | bits xor 2",
79                result: Some(Value::test_list(vec![
80                    Value::test_int(10),
81                    Value::test_int(1),
82                    Value::test_int(0),
83                ])),
84            },
85            Example {
86                description: "Apply bitwise xor to binary data",
87                example: "0x[ca fe] | bits xor 0x[ba be]",
88                result: Some(Value::test_binary(vec![0x70, 0x40])),
89            },
90            Example {
91                description: "Apply bitwise xor to binary data of varying lengths with specified endianness",
92                example: "0x[ca fe] | bits xor 0x[aa] --endian big",
93                result: Some(Value::test_binary(vec![0xca, 0x54])),
94            },
95            Example {
96                description: "Apply bitwise xor to input binary data smaller than the operand",
97                example: "0x[ff] | bits xor 0x[12 34 56] --endian little",
98                result: Some(Value::test_binary(vec![0xed, 0x34, 0x56])),
99            },
100        ]
101    }
102}
103
104#[cfg(test)]
105mod test {
106    use super::*;
107
108    #[test]
109    fn test_examples() -> nu_test_support::Result {
110        nu_test_support::test().examples(BitsXor)
111    }
112}