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