Fix panic in rotate; Add safe record creation function (#11718)

<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx

you can also mention related issues, PRs or discussions!
-->

# Description
<!--
Thank you for improving Nushell. Please, check our [contributing
guide](../CONTRIBUTING.md) and talk to the core team before making major
changes.

Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.
-->

Fixes https://github.com/nushell/nushell/issues/11716

The problem is in our [record creation
API](0d518bf813/crates/nu-protocol/src/value/record.rs (L33))
which panics if the numbers of columns and values are different. I added
a safe variant that returns a `Result` and used it in the `rotate`
command.

## TODO in another PR:

Go through all `from_raw_cols_vals_unchecked()` (this includes the
`record!` macro which uses the unchecked version) and make sure that
either
a) it is guaranteed the number of cols and vals is the same, or
b) convert the call to `from_raw_cols_vals()`

Reason: Nushell should never panic.

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->

# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.

Make sure you've run and fixed any issues with these commands:

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use std testing; testing run-tests --path
crates/nu-std"` to run the tests for the standard library

> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
This commit is contained in:
Jakub Žádník
2024-02-03 13:23:16 +02:00
committed by GitHub
parent c7a8aac883
commit b8d37a7541
19 changed files with 107 additions and 45 deletions

View File

@ -33,7 +33,7 @@ impl Command for SchemaDF {
description: "Dataframe schema",
example: r#"[[a b]; [1 "foo"] [3 "bar"]] | dfr into-df | dfr schema"#,
result: Some(Value::record(
Record::from_raw_cols_vals(
Record::from_raw_cols_vals_unchecked(
vec!["a".to_string(), "b".to_string()],
vec![
Value::string("i64", Span::test_data()),
@ -98,7 +98,7 @@ fn datatype_list(span: Span) -> Value {
]
.iter()
.map(|(dtype, note)| {
Value::record(Record::from_raw_cols_vals(
Value::record(Record::from_raw_cols_vals_unchecked(
vec!["dtype".to_string(), "note".to_string()],
vec![Value::string(*dtype, span), Value::string(*note, span)],
),span)

View File

@ -1041,7 +1041,7 @@ fn series_to_values(
.iter()
.map(|field| field.name.to_string())
.collect();
let record = Record::from_raw_cols_vals(cols, vals?);
let record = Record::from_raw_cols_vals_unchecked(cols, vals?);
Ok(Value::record(record, span))
})
.collect();
@ -1149,7 +1149,7 @@ fn any_value_to_value(any_value: &AnyValue, span: Span) -> Result<Value, ShellEr
.map(|f| f.name().to_string())
.collect();
Ok(Value::Record {
val: Record::from_raw_cols_vals(fields, values?),
val: Record::from_raw_cols_vals_unchecked(fields, values?),
internal_span: span,
})
}

View File

@ -160,7 +160,7 @@ impl NuDataFrame {
conversion::insert_record(
&mut column_values,
Record::from_raw_cols_vals(cols, vals),
Record::from_raw_cols_vals_unchecked(cols, vals),
&maybe_schema,
)?
}

View File

@ -45,7 +45,7 @@ fn fields_to_value(fields: impl Iterator<Item = Field>, span: Span) -> Value {
})
.unzip();
let record = Record::from_raw_cols_vals(cols, vals);
let record = Record::from_raw_cols_vals_unchecked(cols, vals);
Value::record(record, Span::unknown())
}
@ -193,7 +193,7 @@ mod test {
#[test]
fn test_value_to_schema() {
let value = Value::Record {
val: Record::from_raw_cols_vals(
val: Record::from_raw_cols_vals_unchecked(
vec!["name".into(), "age".into(), "address".into()],
vec![
Value::String {
@ -205,7 +205,7 @@ mod test {
internal_span: Span::test_data(),
},
Value::Record {
val: Record::from_raw_cols_vals(
val: Record::from_raw_cols_vals_unchecked(
vec!["street".into(), "city".into()],
vec![
Value::String {