Repository: nushell/nushell
File: crates/nu-command/src/filters/length.rs (Rust)

Code before:
            },
        ]
    }
}

fn length_row(call: &Call, input: PipelineData) -> Result<PipelineData, ShellError> {
    let span = input.span().unwrap_or(call.head);
    match input {
        PipelineData::Value(Value::Nothing { .. }, ..) => {
            Ok(Value::int(0, call.head).into_pipeline_data())
        }
        // I added this here because input_output_type() wasn't catching a record
        // being sent in as input from echo. e.g. "echo {a:1 b:2} | length"
        PipelineData::Value(Value::Record { .. }, ..) => {
            Err(ShellError::OnlySupportsThisInputType {
                exp_input_type: "list, and table".into(),
                wrong_type: "record".into(),
                dst_span: call.head,
                src_span: span,
            })
        }
        PipelineData::Value(Value::Binary { val, .. }, ..) => {
            Ok(Value::int(val.len() as i64, call.head).into_pipeline_data())
        }
        PipelineData::ByteStream(s, _) => {
            Ok(Value::int(s.into_bytes()?.len() as i64, call.head).into_pipeline_data())
        }
        _ => {
            let mut count: i64 = 0;
            // Check for and propagate errors
            for value in input.into_iter() {
                if let Value::Error { error, .. } = value {
                    return Err(*error);
                }
                count += 1
            }
            Ok(Value::int(count, call.head).into_pipeline_data())
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_examples() {
        use crate::test_examples;

        test_examples(Length {})
    }

Review comment (suggestion):
Note that `ByteStream`s can have type string, binary, or unknown, see:

https://github.com/nushell/nushell/blob/1c3ff179bc575a022b6fa71dfce190c522b705ce/crates/nu-protocol/srhc/pipeline/byte_stream.rs#L83

So, this section of code should check that the byte stream is type unknown or binary (and not string).

Also, it would be nice to get the length of byte stream without having to collect the whole stream into memory (`into_bytes` collects into a `Vec`).

Code after:
                example: "0x[01 02] | length",
                result: Some(Value::test_int(2)),
            },
        ]
    }
}

fn length_row(call: &Call, input: PipelineData) -> Result<PipelineData, ShellError> {
    let span = input.span().unwrap_or(call.head);
    match input {
        PipelineData::Value(Value::Nothing { .. }, ..) => {
            Ok(Value::int(0, call.head).into_pipeline_data())
        }
        // I added this here because input_output_type() wasn't catching a record
        // being sent in as input from echo. e.g. "echo {a:1 b:2} | length"
        PipelineData::Value(Value::Record { .. }, ..) => {
            Err(ShellError::OnlySupportsThisInputType {
                exp_input_type: "list, and table".into(),
                wrong_type: "record".into(),
                dst_span: call.head,
                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
            for value in input.into_iter() {
                if let Value::Error { error, .. } = value {
                    return Err(*error);
                }
                count += 1
            }
            Ok(Value::int(count, call.head).into_pipeline_data())
        }
    }
}

#[cfg(test)]