diff --git a/crates/nu-command/src/bits/mod.rs b/crates/nu-command/src/bits/mod.rs index 30c27debcf..016081db32 100644 --- a/crates/nu-command/src/bits/mod.rs +++ b/crates/nu-command/src/bits/mod.rs @@ -1,7 +1,11 @@ mod and; mod bits_; mod not; +mod or; +mod xor; pub use and::SubCommand as BitsAnd; pub use bits_::Bits; pub use not::SubCommand as BitsNot; +pub use or::SubCommand as BitsOr; +pub use xor::SubCommand as BitsXor; diff --git a/crates/nu-command/src/bits/not.rs b/crates/nu-command/src/bits/not.rs index 227003e396..7bb3122885 100644 --- a/crates/nu-command/src/bits/not.rs +++ b/crates/nu-command/src/bits/not.rs @@ -39,7 +39,7 @@ impl Command for SubCommand { } fn usage(&self) -> &str { - "performs logical negation on each bit" + "Performs logical negation on each bit" } fn search_terms(&self) -> Vec<&str> { diff --git a/crates/nu-command/src/bits/or.rs b/crates/nu-command/src/bits/or.rs new file mode 100644 index 0000000000..5c551bf185 --- /dev/null +++ b/crates/nu-command/src/bits/or.rs @@ -0,0 +1,100 @@ +use nu_engine::CallExt; +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EngineState, Stack}; +use nu_protocol::{ + Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, +}; + +#[derive(Clone)] +pub struct SubCommand; + +impl Command for SubCommand { + fn name(&self) -> &str { + "bits or" + } + + fn signature(&self) -> Signature { + Signature::build("bits or") + .required( + "target", + SyntaxShape::Int, + "target integer to perform bit or", + ) + .category(Category::Bits) + } + + fn usage(&self) -> &str { + "Performs bitwise or for integers" + } + + fn search_terms(&self) -> Vec<&str> { + vec!["logic or"] + } + + fn run( + &self, + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + let head = call.head; + let target: i64 = call.req(engine_state, stack, 0)?; + + input.map( + move |value| operate(value, target, head), + engine_state.ctrlc.clone(), + ) + } + + fn examples(&self) -> Vec { + vec![ + Example { + description: "Apply bits or to two numbers", + example: "2 | bits or 6", + result: Some(Value::Int { + val: 6, + span: Span::test_data(), + }), + }, + Example { + description: "Apply logical or to a list of numbers", + example: "[8 3 2] | bits or 2", + result: Some(Value::List { + vals: vec![Value::test_int(10), Value::test_int(3), Value::test_int(2)], + span: Span::test_data(), + }), + }, + ] + } +} + +fn operate(value: Value, target: i64, head: Span) -> Value { + match value { + Value::Int { val, span } => Value::Int { + val: val | target, + span, + }, + other => Value::Error { + error: ShellError::UnsupportedInput( + format!( + "Only integer values are supported, input type: {:?}", + other.get_type() + ), + other.span().unwrap_or(head), + ), + }, + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_examples() { + use crate::test_examples; + + test_examples(SubCommand {}) + } +} diff --git a/crates/nu-command/src/bits/xor.rs b/crates/nu-command/src/bits/xor.rs new file mode 100644 index 0000000000..394ea8a3b5 --- /dev/null +++ b/crates/nu-command/src/bits/xor.rs @@ -0,0 +1,100 @@ +use nu_engine::CallExt; +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EngineState, Stack}; +use nu_protocol::{ + Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, +}; + +#[derive(Clone)] +pub struct SubCommand; + +impl Command for SubCommand { + fn name(&self) -> &str { + "bits xor" + } + + fn signature(&self) -> Signature { + Signature::build("bits xor") + .required( + "target", + SyntaxShape::Int, + "target integer to perform bit xor", + ) + .category(Category::Bits) + } + + fn usage(&self) -> &str { + "Performs bitwise xor for integers" + } + + fn search_terms(&self) -> Vec<&str> { + vec!["logic xor"] + } + + fn run( + &self, + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + let head = call.head; + let target: i64 = call.req(engine_state, stack, 0)?; + + input.map( + move |value| operate(value, target, head), + engine_state.ctrlc.clone(), + ) + } + + fn examples(&self) -> Vec { + vec![ + Example { + description: "Apply bits xor to two numbers", + example: "2 | bits xor 2", + result: Some(Value::Int { + val: 0, + span: Span::test_data(), + }), + }, + Example { + description: "Apply logical xor to a list of numbers", + example: "[8 3 2] | bits xor 2", + result: Some(Value::List { + vals: vec![Value::test_int(10), Value::test_int(1), Value::test_int(0)], + span: Span::test_data(), + }), + }, + ] + } +} + +fn operate(value: Value, target: i64, head: Span) -> Value { + match value { + Value::Int { val, span } => Value::Int { + val: val ^ target, + span, + }, + other => Value::Error { + error: ShellError::UnsupportedInput( + format!( + "Only integer values are supported, input type: {:?}", + other.get_type() + ), + other.span().unwrap_or(head), + ), + }, + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_examples() { + use crate::test_examples; + + test_examples(SubCommand {}) + } +} diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index c281025b1a..c5d2a00c45 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -212,6 +212,8 @@ pub fn create_default_context() -> EngineState { Bits, BitsAnd, BitsNot, + BitsOr, + BitsXor, } // Bytes diff --git a/src/tests/test_bits.rs b/src/tests/test_bits.rs index eae60bcdf3..ada74f4b16 100644 --- a/src/tests/test_bits.rs +++ b/src/tests/test_bits.rs @@ -12,5 +12,35 @@ fn bits_and_negative() -> TestResult { #[test] fn bits_and_list() -> TestResult { - run_test("[1 2 3 8 9 10] | bits and 2 | str collect", "022002") + run_test("[1 2 3 8 9 10] | bits and 2 | str collect '.'", "0.2.2.0.0.2") +} + +#[test] +fn bits_or() -> TestResult { + run_test("2 | bits or 3", "3") +} + +#[test] +fn bits_or_negative() -> TestResult { + run_test("-3 | bits or 5", "-3") +} + +#[test] +fn bits_or_list() -> TestResult { + run_test("[1 2 3 8 9 10] | bits or 2 | str collect '.'", "3.2.3.10.11.10") +} + +#[test] +fn bits_xor() -> TestResult { + run_test("2 | bits xor 3", "1") +} + +#[test] +fn bits_xor_negative() -> TestResult { + run_test("-3 | bits xor 5", "-8") +} + +#[test] +fn bits_xor_list() -> TestResult { + run_test("[1 2 3 8 9 10] | bits xor 2 | str collect '.'", "3.0.1.10.11.8") }