mirror of
https://github.com/nushell/nushell
synced 2024-12-27 21:43:09 +00:00
Binary into int (#5941)
* Add support for binary to into int * Add test
This commit is contained in:
parent
4e90b478b7
commit
2ac5b0480a
4 changed files with 51 additions and 7 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2565,6 +2565,7 @@ dependencies = [
|
||||||
"Inflector",
|
"Inflector",
|
||||||
"alphanumeric-sort",
|
"alphanumeric-sort",
|
||||||
"base64",
|
"base64",
|
||||||
|
"byteorder",
|
||||||
"bytesize",
|
"bytesize",
|
||||||
"calamine",
|
"calamine",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|
|
@ -28,6 +28,7 @@ nu-ansi-term = "0.46.0"
|
||||||
# Potential dependencies for extras
|
# Potential dependencies for extras
|
||||||
alphanumeric-sort = "1.4.4"
|
alphanumeric-sort = "1.4.4"
|
||||||
base64 = "0.13.0"
|
base64 = "0.13.0"
|
||||||
|
byteorder = "1.4.3"
|
||||||
bytesize = "1.1.0"
|
bytesize = "1.1.0"
|
||||||
calamine = "0.18.0"
|
calamine = "0.18.0"
|
||||||
chrono = { version = "0.4.19", features = ["serde"] }
|
chrono = { version = "0.4.19", features = ["serde"] }
|
||||||
|
|
|
@ -8,6 +8,7 @@ use nu_protocol::{
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
radix: Option<Value>,
|
radix: Option<Value>,
|
||||||
column_paths: Vec<CellPath>,
|
column_paths: Vec<CellPath>,
|
||||||
|
little_endian: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -21,6 +22,7 @@ impl Command for SubCommand {
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("into int")
|
Signature::build("into int")
|
||||||
.named("radix", SyntaxShape::Number, "radix of integer", Some('r'))
|
.named("radix", SyntaxShape::Number, "radix of integer", Some('r'))
|
||||||
|
.switch("little-endian", "use little-endian byte decoding", None)
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
SyntaxShape::CellPath,
|
SyntaxShape::CellPath,
|
||||||
|
@ -114,6 +116,7 @@ fn into_int(
|
||||||
|
|
||||||
let options = Arguments {
|
let options = Arguments {
|
||||||
radix: call.get_flag(engine_state, stack, "radix")?,
|
radix: call.get_flag(engine_state, stack, "radix")?,
|
||||||
|
little_endian: call.has_flag("little-endian"),
|
||||||
column_paths: call.rest(engine_state, stack, 0)?,
|
column_paths: call.rest(engine_state, stack, 0)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -135,13 +138,13 @@ fn into_int(
|
||||||
input.map(
|
input.map(
|
||||||
move |v| {
|
move |v| {
|
||||||
if options.column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
action(&v, head, radix)
|
action(&v, head, radix, options.little_endian)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
for path in &options.column_paths {
|
for path in &options.column_paths {
|
||||||
let r = ret.update_cell_path(
|
let r = ret.update_cell_path(
|
||||||
&path.members,
|
&path.members,
|
||||||
Box::new(move |old| action(old, head, radix)),
|
Box::new(move |old| action(old, head, radix, options.little_endian)),
|
||||||
);
|
);
|
||||||
if let Err(error) = r {
|
if let Err(error) = r {
|
||||||
return Value::Error { error };
|
return Value::Error { error };
|
||||||
|
@ -155,7 +158,7 @@ fn into_int(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn action(input: &Value, span: Span, radix: u32) -> Value {
|
pub fn action(input: &Value, span: Span, radix: u32, little_endian: bool) -> Value {
|
||||||
match input {
|
match input {
|
||||||
Value::Int { val: _, .. } => {
|
Value::Int { val: _, .. } => {
|
||||||
if radix == 10 {
|
if radix == 10 {
|
||||||
|
@ -190,6 +193,33 @@ pub fn action(input: &Value, span: Span, radix: u32) -> Value {
|
||||||
val: val.timestamp(),
|
val: val.timestamp(),
|
||||||
span,
|
span,
|
||||||
},
|
},
|
||||||
|
Value::Binary { val, span } => {
|
||||||
|
use byteorder::{BigEndian, ByteOrder, LittleEndian};
|
||||||
|
|
||||||
|
let mut val = val.to_vec();
|
||||||
|
|
||||||
|
if little_endian {
|
||||||
|
while val.len() < 8 {
|
||||||
|
val.push(0);
|
||||||
|
}
|
||||||
|
val.resize(8, 0);
|
||||||
|
|
||||||
|
Value::Int {
|
||||||
|
val: LittleEndian::read_i64(&val),
|
||||||
|
span: *span,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while val.len() < 8 {
|
||||||
|
val.insert(0, 0);
|
||||||
|
}
|
||||||
|
val.resize(8, 0);
|
||||||
|
|
||||||
|
Value::Int {
|
||||||
|
val: BigEndian::read_i64(&val),
|
||||||
|
span: *span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => Value::Error {
|
_ => Value::Error {
|
||||||
error: ShellError::UnsupportedInput(
|
error: ShellError::UnsupportedInput(
|
||||||
format!("'into int' for unsupported type '{}'", input.get_type()),
|
format!("'into int' for unsupported type '{}'", input.get_type()),
|
||||||
|
@ -294,21 +324,21 @@ mod test {
|
||||||
let word = Value::test_string("10");
|
let word = Value::test_string("10");
|
||||||
let expected = Value::test_int(10);
|
let expected = Value::test_int(10);
|
||||||
|
|
||||||
let actual = action(&word, Span::test_data(), 10);
|
let actual = action(&word, Span::test_data(), 10, false);
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn turns_binary_to_integer() {
|
fn turns_binary_to_integer() {
|
||||||
let s = Value::test_string("0b101");
|
let s = Value::test_string("0b101");
|
||||||
let actual = action(&s, Span::test_data(), 10);
|
let actual = action(&s, Span::test_data(), 10, false);
|
||||||
assert_eq!(actual, Value::test_int(5));
|
assert_eq!(actual, Value::test_int(5));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn turns_hex_to_integer() {
|
fn turns_hex_to_integer() {
|
||||||
let s = Value::test_string("0xFF");
|
let s = Value::test_string("0xFF");
|
||||||
let actual = action(&s, Span::test_data(), 16);
|
let actual = action(&s, Span::test_data(), 16, false);
|
||||||
assert_eq!(actual, Value::test_int(255));
|
assert_eq!(actual, Value::test_int(255));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,7 +346,7 @@ mod test {
|
||||||
fn communicates_parsing_error_given_an_invalid_integerlike_string() {
|
fn communicates_parsing_error_given_an_invalid_integerlike_string() {
|
||||||
let integer_str = Value::test_string("36anra");
|
let integer_str = Value::test_string("36anra");
|
||||||
|
|
||||||
let actual = action(&integer_str, Span::test_data(), 10);
|
let actual = action(&integer_str, Span::test_data(), 10, false);
|
||||||
|
|
||||||
assert_eq!(actual.get_type(), Error)
|
assert_eq!(actual.get_type(), Error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,3 +35,15 @@ fn into_int_int() {
|
||||||
|
|
||||||
assert!(actual.out.contains('1'));
|
assert!(actual.out.contains('1'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn into_int_binary() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: ".", pipeline(
|
||||||
|
r#"
|
||||||
|
echo 0x[01010101] | into int
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
|
||||||
|
assert!(actual.out.contains("16843009"));
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue