Create Record type (#10103)

# Description
This PR creates a new `Record` type to reduce duplicate code and
possibly bugs as well. (This is an edited version of #9648.)
- `Record` implements `FromIterator` and `IntoIterator` and so can be
iterated over or collected into. For example, this helps with
conversions to and from (hash)maps. (Also, no more
`cols.iter().zip(vals)`!)
- `Record` has a `push(col, val)` function to help insure that the
number of columns is equal to the number of values. I caught a few
potential bugs thanks to this (e.g. in the `ls` command).
- Finally, this PR also adds a `record!` macro that helps simplify
record creation. It is used like so:
   ```rust
   record! {
       "key1" => some_value,
       "key2" => Value::string("text", span),
       "key3" => Value::int(optional_int.unwrap_or(0), span),
       "key4" => Value::bool(config.setting, span),
   }
   ```
Since macros hinder formatting, etc., the right hand side values should
be relatively short and sweet like the examples above.

Where possible, prefer `record!` or `.collect()` on an iterator instead
of multiple `Record::push`s, since the first two automatically set the
record capacity and do less work overall.

# User-Facing Changes
Besides the changes in `nu-protocol` the only other breaking changes are
to `nu-table::{ExpandedTable::build_map, JustTable::kv_table}`.
This commit is contained in:
Ian Manske
2023-08-24 19:50:29 +00:00
committed by GitHub
parent 030e749fe7
commit 8da27a1a09
195 changed files with 4211 additions and 6245 deletions

View File

@@ -2,7 +2,7 @@ use std::io::Result;
use nu_protocol::{
engine::{EngineState, Stack},
Value,
record, Value,
};
use crate::{
@@ -158,10 +158,14 @@ impl ViewCommand for ConfigCmd {
fn create_default_value() -> Value {
let span = NuSpan::unknown();
let record = |i: usize| Value::Record {
cols: vec![String::from("key"), String::from("value")],
vals: vec![nu_str(format!("key-{i}")), nu_str(format!("{i}"))],
span,
let record = |i: usize| {
Value::record(
record! {
"key" => nu_str(format!("key-{i}")),
"value" => nu_str(format!("{i}")),
},
span,
)
};
Value::List {

View File

@@ -1,6 +1,6 @@
use nu_protocol::{
engine::{EngineState, Stack},
Value,
record, Value,
};
use ratatui::layout::Rect;
use std::collections::HashMap;
@@ -157,8 +157,8 @@ fn convert_styles_value(value: &mut Value) {
convert_styles_value(value);
}
}
Value::Record { vals, .. } => {
for value in vals {
Value::Record { val, .. } => {
for value in &mut val.vals {
convert_styles_value(value);
}
}
@@ -168,17 +168,13 @@ fn convert_styles_value(value: &mut Value) {
fn convert_style_from_string(s: &str) -> Option<Value> {
let style = nu_json::from_str::<nu_color_config::NuStyle>(s).ok()?;
let cols = vec![String::from("bg"), String::from("fg"), String::from("attr")];
let vals = vec![
Value::string(style.bg.unwrap_or_default(), NuSpan::unknown()),
Value::string(style.fg.unwrap_or_default(), NuSpan::unknown()),
Value::string(style.attr.unwrap_or_default(), NuSpan::unknown()),
];
Some(Value::Record {
cols,
vals,
span: NuSpan::unknown(),
})
Some(Value::record(
record! {
"bg" => Value::string(style.bg.unwrap_or_default(), NuSpan::unknown()),
"fg" => Value::string(style.fg.unwrap_or_default(), NuSpan::unknown()),
"attr" => Value::string(style.attr.unwrap_or_default(), NuSpan::unknown()),
},
NuSpan::unknown(),
))
}

View File

@@ -4,7 +4,7 @@ use std::io::{self, Result};
use crossterm::event::KeyEvent;
use nu_protocol::{
engine::{EngineState, Stack},
Value,
record, Record, Value,
};
use ratatui::layout::Rect;
@@ -169,11 +169,7 @@ fn help_frame_data(
let (cols, mut vals) = help_manual_data(manual, aliases);
let vals = vals.remove(0);
Value::Record {
cols,
vals,
span: NuSpan::unknown(),
}
Value::record(Record { cols, vals }, NuSpan::unknown())
})
.collect();
let commands = Value::List {
@@ -192,10 +188,14 @@ fn help_manual_data(manual: &HelpManual, aliases: &[String]) -> (Vec<String>, Ve
let arguments = manual
.arguments
.iter()
.map(|e| Value::Record {
cols: vec![String::from("example"), String::from("description")],
vals: vec![nu_str(&e.example), nu_str(&e.description)],
span: NuSpan::unknown(),
.map(|e| {
Value::record(
record! {
"example" => nu_str(&e.example),
"description" => nu_str(&e.description),
},
NuSpan::unknown(),
)
})
.collect();
@@ -207,10 +207,14 @@ fn help_manual_data(manual: &HelpManual, aliases: &[String]) -> (Vec<String>, Ve
let examples = manual
.examples
.iter()
.map(|e| Value::Record {
cols: vec![String::from("example"), String::from("description")],
vals: vec![nu_str(&e.example), nu_str(&e.description)],
span: NuSpan::unknown(),
.map(|e| {
Value::record(
record! {
"example" => nu_str(&e.example),
"description" => nu_str(&e.description),
},
NuSpan::unknown(),
)
})
.collect();
let examples = Value::List {
@@ -221,14 +225,15 @@ fn help_manual_data(manual: &HelpManual, aliases: &[String]) -> (Vec<String>, Ve
let inputs = manual
.input
.iter()
.map(|e| Value::Record {
cols: vec![
String::from("name"),
String::from("context"),
String::from("description"),
],
vals: vec![nu_str(&e.code), nu_str(&e.context), nu_str(&e.description)],
span: NuSpan::unknown(),
.map(|e| {
Value::record(
record! {
"name" => nu_str(&e.code),
"context" => nu_str(&e.context),
"description" => nu_str(&e.description),
},
NuSpan::unknown(),
)
})
.collect();
let inputs = Value::List {
@@ -243,10 +248,14 @@ fn help_manual_data(manual: &HelpManual, aliases: &[String]) -> (Vec<String>, Ve
let values = o
.values
.iter()
.map(|v| Value::Record {
cols: vec![String::from("example"), String::from("description")],
vals: vec![nu_str(&v.example), nu_str(&v.description)],
span: NuSpan::unknown(),
.map(|v| {
Value::record(
record! {
"example" => nu_str(&v.example),
"description" => nu_str(&v.description),
},
NuSpan::unknown(),
)
})
.collect();
let values = Value::List {
@@ -254,21 +263,15 @@ fn help_manual_data(manual: &HelpManual, aliases: &[String]) -> (Vec<String>, Ve
span: NuSpan::unknown(),
};
Value::Record {
cols: vec![
String::from("name"),
String::from("context"),
String::from("description"),
String::from("values"),
],
vals: vec![
nu_str(&o.group),
nu_str(&o.key),
nu_str(&o.description),
values,
],
span: NuSpan::unknown(),
}
Value::record(
record! {
"name" => nu_str(&o.group),
"context" => nu_str(&o.key),
"description" => nu_str(&o.description),
"values" => values,
},
NuSpan::unknown(),
)
})
.collect();
let configuration = Value::List {