support binary input in length (#14224)

Closes #13874

# User-Facing Changes

`length` now supports binary input:

```nushell
> random binary 1kb | length
1000
```
This commit is contained in:
Solomon 2024-11-03 20:39:24 -07:00 committed by GitHub
parent d289c773d0
commit 8b19399b13
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 38 additions and 2 deletions

View File

@ -1,3 +1,5 @@
use std::io::Read;
use nu_engine::command_prelude::*;
#[derive(Clone)]
@ -9,12 +11,15 @@ impl Command for Length {
}
fn description(&self) -> &str {
"Count the number of items in an input list or rows in a table."
"Count the number of items in an input list, rows in a table, or bytes in binary data."
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("length")
.input_output_types(vec![(Type::List(Box::new(Type::Any)), Type::Int)])
.input_output_types(vec![
(Type::List(Box::new(Type::Any)), Type::Int),
(Type::Binary, Type::Int),
])
.category(Category::Filters)
}
@ -44,6 +49,11 @@ impl Command for Length {
example: "[{a:1 b:2}, {a:2 b:3}] | length",
result: Some(Value::test_int(2)),
},
Example {
description: "Count the number of bytes in binary data",
example: "0x[01 02] | length",
result: Some(Value::test_int(2)),
},
]
}
}
@ -64,6 +74,19 @@ fn length_row(call: &Call, input: PipelineData) -> Result<PipelineData, ShellErr
src_span: span,
})
}
PipelineData::Value(Value::Binary { val, .. }, ..) => {
Ok(Value::int(val.len() as i64, call.head).into_pipeline_data())
}
PipelineData::ByteStream(stream, _) if stream.type_().is_binary_coercible() => {
Ok(Value::int(
match stream.reader() {
Some(r) => r.bytes().count() as i64,
None => 0,
},
call.head,
)
.into_pipeline_data())
}
_ => {
let mut count: i64 = 0;
// Check for and propagate errors

View File

@ -1,4 +1,6 @@
use nu_test_support::fs::Stub::FileWithContent;
use nu_test_support::nu;
use nu_test_support::playground::Playground;
#[test]
fn length_columns_in_cal_table() {
@ -20,3 +22,14 @@ fn length_fails_on_echo_record() {
assert!(actual.err.contains("only_supports_this_input_type"));
}
#[test]
fn length_byte_stream() {
Playground::setup("length_bytes", |dirs, sandbox| {
sandbox.mkdir("length_bytes");
sandbox.with_files(&[FileWithContent("data.txt", "😀")]);
let actual = nu!(cwd: dirs.test(), "open data.txt | length");
assert_eq!(actual.out, "4");
});
}