nu_cmd_extra/extra/bits/
and.rs

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