diff --git a/crates/nu-cli/src/completions/variable_completions.rs b/crates/nu-cli/src/completions/variable_completions.rs index ab755d1d85..b82dc0dc41 100644 --- a/crates/nu-cli/src/completions/variable_completions.rs +++ b/crates/nu-cli/src/completions/variable_completions.rs @@ -237,9 +237,9 @@ fn nested_suggestions( match value { Value::Record { val, .. } => { // Add all the columns as completion - for item in val.cols { + for (col, _) in val.into_iter() { output.push(Suggestion { - value: item, + value: col, description: None, extra: None, span: current_span, diff --git a/crates/nu-cmd-base/src/formats/to/delimited.rs b/crates/nu-cmd-base/src/formats/to/delimited.rs index 97f63affe0..d7084bcbc1 100644 --- a/crates/nu-cmd-base/src/formats/to/delimited.rs +++ b/crates/nu-cmd-base/src/formats/to/delimited.rs @@ -6,7 +6,7 @@ pub fn merge_descriptors(values: &[Value]) -> Vec { let mut seen: IndexSet = indexset! {}; for value in values { let data_descriptors = match value { - Value::Record { val, .. } => val.cols.clone(), + Value::Record { val, .. } => val.columns().cloned().collect(), _ => vec!["".to_string()], }; for desc in data_descriptors { diff --git a/crates/nu-command/src/database/commands/into_sqlite.rs b/crates/nu-command/src/database/commands/into_sqlite.rs index a420eb7bb0..3dacc338ea 100644 --- a/crates/nu-command/src/database/commands/into_sqlite.rs +++ b/crates/nu-command/src/database/commands/into_sqlite.rs @@ -128,8 +128,7 @@ fn action( "({})", match list_value { Value::Record { val, .. } => { - val.vals - .iter() + val.values() .map(|rec_val| { format!("'{}'", nu_value_to_string(rec_val.clone(), "")) }) diff --git a/crates/nu-command/src/filters/columns.rs b/crates/nu-command/src/filters/columns.rs index 09b3d8be00..e21041ccfc 100644 --- a/crates/nu-command/src/filters/columns.rs +++ b/crates/nu-command/src/filters/columns.rs @@ -124,9 +124,8 @@ fn getcol( }) } Value::Record { val, .. } => Ok(val - .cols .into_iter() - .map(move |x| Value::string(x, head)) + .map(move |(x, _)| Value::string(x, head)) .into_pipeline_data(ctrlc) .set_metadata(metadata)), // Propagate errors diff --git a/crates/nu-command/src/filters/default.rs b/crates/nu-command/src/filters/default.rs index a8cf436aff..bd8ab1a113 100644 --- a/crates/nu-command/src/filters/default.rs +++ b/crates/nu-command/src/filters/default.rs @@ -91,17 +91,15 @@ fn default( Value::Record { val: mut record, .. } => { - let mut idx = 0; let mut found = false; - while idx < record.len() { - if record.cols[idx] == column.item { + for (col, val) in record.iter_mut() { + if *col == column.item { found = true; - if matches!(record.vals[idx], Value::Nothing { .. }) { - record.vals[idx] = value.clone(); + if matches!(val, Value::Nothing { .. }) { + *val = value.clone(); } } - idx += 1; } if !found { diff --git a/crates/nu-command/src/filters/flatten.rs b/crates/nu-command/src/filters/flatten.rs index 7650e741cf..8b3af912ef 100644 --- a/crates/nu-command/src/filters/flatten.rs +++ b/crates/nu-command/src/filters/flatten.rs @@ -314,7 +314,7 @@ fn flat_value(columns: &[CellPath], item: &Value, name_tag: Span, all: bool) -> // this can avoid output column order changed. if index == parent_column_index { for (col, val) in inner_cols.iter().zip(inner_vals.iter()) { - if record.cols.contains(col) { + if record.contains(col) { record.push(format!("{parent_column_name}_{col}"), val.clone()); } else { record.push(col, val.clone()); @@ -329,7 +329,7 @@ fn flat_value(columns: &[CellPath], item: &Value, name_tag: Span, all: bool) -> // the flattened column may be the last column in the original table. if index == parent_column_index { for (col, val) in inner_cols.iter().zip(inner_vals.iter()) { - if record.cols.contains(col) { + if record.contains(col) { record.push(format!("{parent_column_name}_{col}"), val.clone()); } else { record.push(col, val.clone()); diff --git a/crates/nu-command/src/filters/headers.rs b/crates/nu-command/src/filters/headers.rs index 086386f186..a21908b180 100644 --- a/crates/nu-command/src/filters/headers.rs +++ b/crates/nu-command/src/filters/headers.rs @@ -129,7 +129,7 @@ fn extract_headers( let span = value.span(); match value { Value::Record { val: record, .. } => { - for v in &record.vals { + for v in record.values() { if !is_valid_header(v) { return Err(ShellError::TypeMismatch { err_message: "needs compatible type: Null, String, Bool, Float, Int" @@ -139,10 +139,9 @@ fn extract_headers( } } - let old_headers = record.cols.clone(); + let old_headers = record.columns().cloned().collect(); let new_headers = record - .vals - .iter() + .values() .enumerate() .map(|(idx, value)| { let col = value.into_string("", config); diff --git a/crates/nu-command/src/filters/merge.rs b/crates/nu-command/src/filters/merge.rs index de99f73643..638c762550 100644 --- a/crates/nu-command/src/filters/merge.rs +++ b/crates/nu-command/src/filters/merge.rs @@ -153,20 +153,12 @@ repeating this process with row 1, and so on."# } } +// TODO: rewrite to mutate the input record fn do_merge(input_record: &Record, to_merge_record: &Record) -> Record { let mut result = input_record.clone(); for (col, val) in to_merge_record { - let pos = result.cols.iter().position(|c| c == col); - // if find, replace existing data, else, push new data. - match pos { - Some(index) => { - result.vals[index] = val.clone(); - } - None => { - result.push(col, val.clone()); - } - } + result.insert(col, val.clone()); } result } diff --git a/crates/nu-command/src/filters/move_.rs b/crates/nu-command/src/filters/move_.rs index bf11918697..5f700ba1dc 100644 --- a/crates/nu-command/src/filters/move_.rs +++ b/crates/nu-command/src/filters/move_.rs @@ -197,7 +197,7 @@ fn move_record_columns( // Check if before/after column exist match &before_or_after.item { BeforeOrAfter::After(after) => { - if !record.cols.contains(after) { + if !record.contains(after) { return Err(ShellError::GenericError( "Cannot move columns".to_string(), "column does not exist".to_string(), @@ -208,7 +208,7 @@ fn move_record_columns( } } BeforeOrAfter::Before(before) => { - if !record.cols.contains(before) { + if !record.contains(before) { return Err(ShellError::GenericError( "Cannot move columns".to_string(), "column does not exist".to_string(), @@ -224,11 +224,7 @@ fn move_record_columns( for column in columns.iter() { let column_str = column.as_string()?; - if let Some(idx) = record - .cols - .iter() - .position(|inp_col| &column_str == inp_col) - { + if let Some(idx) = record.index_of(&column_str) { column_idx.push(idx); } else { return Err(ShellError::GenericError( @@ -249,7 +245,7 @@ fn move_record_columns( out.push(inp_col.clone(), inp_val.clone()); for idx in column_idx.iter() { - if let (Some(col), Some(val)) = (record.cols.get(*idx), record.vals.get(*idx)) { + if let Some((col, val)) = record.get_index(*idx) { out.push(col.clone(), val.clone()); } else { return Err(ShellError::NushellFailedSpanned { @@ -262,7 +258,7 @@ fn move_record_columns( } BeforeOrAfter::Before(before) if before == inp_col => { for idx in column_idx.iter() { - if let (Some(col), Some(val)) = (record.cols.get(*idx), record.vals.get(*idx)) { + if let Some((col, val)) = record.get_index(*idx) { out.push(col.clone(), val.clone()); } else { return Err(ShellError::NushellFailedSpanned { diff --git a/crates/nu-command/src/filters/sort.rs b/crates/nu-command/src/filters/sort.rs index 8146f55470..76fc79601e 100644 --- a/crates/nu-command/src/filters/sort.rs +++ b/crates/nu-command/src/filters/sort.rs @@ -254,7 +254,7 @@ pub fn sort( ) -> Result<(), ShellError> { match vec.first() { Some(Value::Record { val, .. }) => { - let columns = val.cols.clone(); + let columns: Vec = val.columns().cloned().collect(); vec.sort_by(|a, b| process(a, b, &columns, span, insensitive, natural)); } _ => { diff --git a/crates/nu-command/src/filters/split_by.rs b/crates/nu-command/src/filters/split_by.rs index f5f93b5aa8..537a01394a 100644 --- a/crates/nu-command/src/filters/split_by.rs +++ b/crates/nu-command/src/filters/split_by.rs @@ -185,15 +185,15 @@ pub fn data_split( let span = v.span(); match v { Value::Record { val: grouped, .. } => { - for (idx, list) in grouped.vals.iter().enumerate() { - match data_group(list, splitter, span) { + for (outer_key, list) in grouped.into_iter() { + match data_group(&list, splitter, span) { Ok(grouped_vals) => { if let Value::Record { val: sub, .. } = grouped_vals { - for (inner_idx, subset) in sub.vals.iter().enumerate() { + for (inner_key, subset) in sub.into_iter() { let s: &mut IndexMap = - splits.entry(sub.cols[inner_idx].clone()).or_default(); + splits.entry(inner_key).or_default(); - s.insert(grouped.cols[idx].clone(), subset.clone()); + s.insert(outer_key.clone(), subset.clone()); } } } diff --git a/crates/nu-command/src/filters/uniq.rs b/crates/nu-command/src/filters/uniq.rs index 426d28dc41..c333351c8b 100644 --- a/crates/nu-command/src/filters/uniq.rs +++ b/crates/nu-command/src/filters/uniq.rs @@ -3,8 +3,8 @@ use itertools::Itertools; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::{ - record, Category, Example, IntoPipelineData, PipelineData, PipelineMetadata, Record, - ShellError, Signature, Span, Type, Value, + record, Category, Example, IntoPipelineData, PipelineData, PipelineMetadata, ShellError, + Signature, Span, Type, Value, }; use std::collections::hash_map::IntoIter; use std::collections::HashMap; @@ -190,10 +190,10 @@ fn clone_to_lowercase(value: &Value) -> Value { Value::list(vec.iter().map(clone_to_lowercase).collect(), span) } Value::Record { val: record, .. } => Value::record( - Record { - cols: record.cols.clone(), - vals: record.vals.iter().map(clone_to_lowercase).collect(), - }, + record + .iter() + .map(|(k, v)| (k.to_owned(), clone_to_lowercase(v))) + .collect(), span, ), other => other.clone(), @@ -204,24 +204,18 @@ fn sort_attributes(val: Value) -> Value { let span = val.span(); match val { Value::Record { val, .. } => { + // TODO: sort inplace let sorted = val .into_iter() .sorted_by(|a, b| a.0.cmp(&b.0)) .collect_vec(); - let sorted_cols = sorted.clone().into_iter().map(|a| a.0).collect_vec(); - let sorted_vals = sorted + let record = sorted .into_iter() - .map(|a| sort_attributes(a.1)) - .collect_vec(); + .map(|(k, v)| (k, sort_attributes(v))) + .collect(); - Value::record( - Record { - cols: sorted_cols, - vals: sorted_vals, - }, - span, - ) + Value::record(record, span) } Value::List { vals, .. } => { Value::list(vals.into_iter().map(sort_attributes).collect_vec(), span) diff --git a/crates/nu-command/src/filters/uniq_by.rs b/crates/nu-command/src/filters/uniq_by.rs index ced8fc0ecb..ccbd6b9b11 100644 --- a/crates/nu-command/src/filters/uniq_by.rs +++ b/crates/nu-command/src/filters/uniq_by.rs @@ -126,7 +126,7 @@ fn validate(vec: &[Value], columns: &[String], span: Span) -> Result<(), ShellEr )); } - if let Some(nonexistent) = nonexistent_column(columns, &record.cols) { + if let Some(nonexistent) = nonexistent_column(columns, record.columns()) { return Err(ShellError::CantFindColumn { col_name: nonexistent, span, diff --git a/crates/nu-command/src/formats/to/md.rs b/crates/nu-command/src/formats/to/md.rs index c882275372..5127f18e38 100644 --- a/crates/nu-command/src/formats/to/md.rs +++ b/crates/nu-command/src/formats/to/md.rs @@ -210,7 +210,7 @@ pub fn group_by(values: PipelineData, head: Span, config: &Config) -> (PipelineD } = val { lists - .entry(record.cols.concat()) + .entry(record.columns().map(|c| c.as_str()).collect::()) .and_modify(|v: &mut Vec| v.push(val.clone())) .or_insert_with(|| vec![val.clone()]); } else { diff --git a/crates/nu-command/src/formats/to/nuon.rs b/crates/nu-command/src/formats/to/nuon.rs index e9429cc9f1..1b5728acd7 100644 --- a/crates/nu-command/src/formats/to/nuon.rs +++ b/crates/nu-command/src/formats/to/nuon.rs @@ -209,7 +209,7 @@ pub fn value_to_string( let mut row = vec![]; if let Value::Record { val, .. } = val { - for val in &val.vals { + for val in val.values() { row.push(value_to_string_without_quotes( val, span, diff --git a/crates/nu-command/src/network/http/client.rs b/crates/nu-command/src/network/http/client.rs index edfbad3040..92549f700d 100644 --- a/crates/nu-command/src/network/http/client.rs +++ b/crates/nu-command/src/network/http/client.rs @@ -602,9 +602,12 @@ fn headers_to_nu(headers: &Headers, span: Span) -> Result Value { match mode { ActionMode::Global => match other { Value::Record { val: record, .. } => { - let new_vals = record.vals.iter().map(|v| action(v, arg, head)).collect(); + let new_record = record + .iter() + .map(|(k, v)| (k.clone(), action(v, arg, head))) + .collect(); - Value::record( - Record { - cols: record.cols.to_vec(), - vals: new_vals, - }, - span, - ) + Value::record(new_record, span) } Value::List { vals, .. } => { let new_vals = vals.iter().map(|v| action(v, arg, head)).collect(); diff --git a/crates/nu-engine/src/column.rs b/crates/nu-engine/src/column.rs index 944a613f79..1507e046da 100644 --- a/crates/nu-engine/src/column.rs +++ b/crates/nu-engine/src/column.rs @@ -19,8 +19,11 @@ pub fn get_columns(input: &[Value]) -> Vec { } // If a column doesn't exist in the input, return it. -pub fn nonexistent_column(inputs: &[String], columns: &[String]) -> Option { - let set: HashSet = HashSet::from_iter(columns.iter().cloned()); +pub fn nonexistent_column<'a, I>(inputs: &[String], columns: I) -> Option +where + I: IntoIterator, +{ + let set: HashSet<&String> = HashSet::from_iter(columns); for input in inputs { if set.contains(input) { diff --git a/crates/nu-explore/src/commands/help.rs b/crates/nu-explore/src/commands/help.rs index 55e15ddb36..f687ca27b2 100644 --- a/crates/nu-explore/src/commands/help.rs +++ b/crates/nu-explore/src/commands/help.rs @@ -165,7 +165,7 @@ fn help_frame_data( let (cols, mut vals) = help_manual_data(manual, aliases); let vals = vals.remove(0); - Value::record(Record { cols, vals }, NuSpan::unknown()) + Value::record(Record::from_raw_cols_vals(cols, vals), NuSpan::unknown()) }) .collect(); let commands = Value::list(commands, NuSpan::unknown()); diff --git a/crates/nu-explore/src/nu_common/value.rs b/crates/nu-explore/src/nu_common/value.rs index 0538b25b1f..94a578aa56 100644 --- a/crates/nu-explore/src/nu_common/value.rs +++ b/crates/nu-explore/src/nu_common/value.rs @@ -90,7 +90,10 @@ fn collect_external_stream( pub fn collect_input(value: Value) -> (Vec, Vec>) { let span = value.span(); match value { - Value::Record { val: record, .. } => (record.cols, vec![record.vals]), + Value::Record { val: record, .. } => { + let (key, val) = record.into_iter().unzip(); + (key, vec![val]) + } Value::List { vals, .. } => { let mut columns = get_columns(&vals); let data = convert_records_to_dataset(&columns, vals); diff --git a/crates/nu-explore/src/pager/mod.rs b/crates/nu-explore/src/pager/mod.rs index d2cc8e18de..4b93c2f943 100644 --- a/crates/nu-explore/src/pager/mod.rs +++ b/crates/nu-explore/src/pager/mod.rs @@ -1041,21 +1041,9 @@ fn set_config(hm: &mut HashMap, path: &[&str], value: Value) -> b match val { Value::Record { val: record, .. } => { if path.len() == 2 { - if record.cols.len() != record.vals.len() { - return false; - } + let key = path[1]; - let key = &path[1]; - - let pos = record.cols.iter().position(|v| v == key); - match pos { - Some(i) => { - record.vals[i] = value; - } - None => { - record.push(*key, value); - } - } + record.insert(key, value); } else { let mut hm2: HashMap = HashMap::new(); for (k, v) in record.iter() { diff --git a/crates/nu-explore/src/views/record/mod.rs b/crates/nu-explore/src/views/record/mod.rs index d908202080..e514702418 100644 --- a/crates/nu-explore/src/views/record/mod.rs +++ b/crates/nu-explore/src/views/record/mod.rs @@ -708,10 +708,7 @@ fn build_table_as_list(v: &RecordView) -> Value { .cloned() .map(|vals| { Value::record( - Record { - cols: headers.clone(), - vals, - }, + Record::from_raw_cols_vals(headers.clone(), vals), NuSpan::unknown(), ) }) @@ -726,7 +723,7 @@ fn build_table_as_record(v: &RecordView) -> Value { let cols = layer.columns.to_vec(); let vals = layer.records.get(0).map_or(Vec::new(), |row| row.clone()); - Value::record(Record { cols, vals }, NuSpan::unknown()) + Value::record(Record::from_raw_cols_vals(cols, vals), NuSpan::unknown()) } fn report_cursor_position(mode: UIMode, cursor: XYCursor) -> String { diff --git a/crates/nu_plugin_example/src/example.rs b/crates/nu_plugin_example/src/example.rs index 643fcb0c1d..2f54b1404c 100644 --- a/crates/nu_plugin_example/src/example.rs +++ b/crates/nu_plugin_example/src/example.rs @@ -67,13 +67,7 @@ impl Example { .map(|v| Value::int(v * i, call.head)) .collect::>(); - Value::record( - Record { - cols: cols.clone(), - vals, - }, - call.head, - ) + Value::record(Record::from_raw_cols_vals(cols.clone(), vals), call.head) }) .collect::>();