Remove lazy records (#12682)

# Description
Removes lazy records from the language, following from the reasons
outlined in #12622. Namely, this should make semantics more clear and
will eliminate concerns regarding maintainability.

# User-Facing Changes
- Breaking change: `lazy make` is removed.
- Breaking change: `describe --collect-lazyrecords` flag is removed.
- `sys` and `debug info` now return regular records.

# After Submitting
- Update nushell book if necessary.
- Explore new `sys` and `debug info` APIs to prevent them from taking
too long (e.g., subcommands or taking an optional column/cell-path
argument).
This commit is contained in:
Ian Manske 2024-05-03 00:36:10 +00:00 committed by GitHub
parent ad6deadf24
commit 847646e44e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 133 additions and 867 deletions

View File

@ -267,24 +267,6 @@ fn nested_suggestions(
output
}
Value::LazyRecord { val, .. } => {
// Add all the columns as completion
for column_name in val.column_names() {
output.push(SemanticSuggestion {
suggestion: Suggestion {
value: column_name.to_string(),
description: None,
style: None,
extra: None,
span: current_span,
append_whitespace: false,
},
kind: Some(kind.clone()),
});
}
output
}
Value::List { vals, .. } => {
for column_name in get_columns(vals.as_slice()) {
output.push(SemanticSuggestion {
@ -321,17 +303,6 @@ fn recursive_value(val: &Value, sublevels: &[Vec<u8>]) -> Result<Value, Span> {
Err(span)
}
}
Value::LazyRecord { val, .. } => {
for col in val.column_names() {
if col.as_bytes() == *sublevel {
let val = val.get_column_value(col).map_err(|_| span)?;
return recursive_value(&val, next_sublevels);
}
}
// Current sublevel value not found
Err(span)
}
Value::List { vals, .. } => {
for col in get_columns(vals.as_slice()) {
if col.as_bytes() == *sublevel {

View File

@ -26,7 +26,6 @@ impl Command for Describe {
"show detailed information about the value",
Some('d'),
)
.switch("collect-lazyrecords", "collect lazy records", Some('l'))
.category(Category::Core)
}
@ -44,21 +43,7 @@ impl Command for Describe {
let options = Options {
no_collect: call.has_flag(engine_state, stack, "no-collect")?,
detailed: call.has_flag(engine_state, stack, "detailed")?,
collect_lazyrecords: call.has_flag(engine_state, stack, "collect-lazyrecords")?,
};
if options.collect_lazyrecords {
nu_protocol::report_error_new(
engine_state,
&ShellError::GenericError {
error: "Deprecated flag".into(),
msg: "the `--collect-lazyrecords` flag is deprecated, since lazy records will be removed in 0.94.0"
.into(),
span: Some(call.head),
help: None,
inner: vec![],
},
);
}
run(Some(engine_state), call, input, options)
}
@ -71,7 +56,6 @@ impl Command for Describe {
let options = Options {
no_collect: call.has_flag_const(working_set, "no-collect")?,
detailed: call.has_flag_const(working_set, "detailed")?,
collect_lazyrecords: call.has_flag_const(working_set, "collect-lazyrecords")?,
};
run(None, call, input, options)
}
@ -89,13 +73,11 @@ impl Command for Describe {
"{shell:'true', uwu:true, features: {bugs:false, multiplatform:true, speed: 10}, fib: [1 1 2 3 5 8], on_save: {|x| print $'Saving ($x)'}, first_commit: 2019-05-10, my_duration: (4min + 20sec)} | describe -d",
result: Some(Value::test_record(record!(
"type" => Value::test_string("record"),
"lazy" => Value::test_bool(false),
"columns" => Value::test_record(record!(
"shell" => Value::test_string("string"),
"uwu" => Value::test_string("bool"),
"features" => Value::test_record(record!(
"type" => Value::test_string("record"),
"lazy" => Value::test_bool(false),
"columns" => Value::test_record(record!(
"bugs" => Value::test_string("bool"),
"multiplatform" => Value::test_string("bool"),
@ -168,7 +150,6 @@ impl Command for Describe {
struct Options {
no_collect: bool,
detailed: bool,
collect_lazyrecords: bool,
}
fn run(
@ -243,7 +224,7 @@ fn run(
if options.no_collect {
Value::string("any", head)
} else {
describe_value(input.into_value(head), head, engine_state, options)?
describe_value(input.into_value(head), head, engine_state, )
}
},
"metadata" => metadata_to_value(metadata, head),
@ -264,7 +245,7 @@ fn run(
if !options.detailed {
Value::string(value.get_type().to_string(), head)
} else {
describe_value(value, head, engine_state, options)?
describe_value(value, head, engine_state)
}
}
};
@ -288,9 +269,8 @@ fn describe_value(
value: Value,
head: nu_protocol::Span,
engine_state: Option<&EngineState>,
options: Options,
) -> Result<Value, ShellError> {
Ok(match value {
) -> Value {
match value {
Value::Custom { val, .. } => Value::record(
record!(
"type" => Value::string("custom", head),
@ -320,14 +300,12 @@ fn describe_value(
std::mem::take(v),
head,
engine_state,
options,
)?);
));
}
Value::record(
record!(
"type" => Value::string("record", head),
"lazy" => Value::bool(false, head),
"columns" => Value::record(val, head),
),
head,
@ -338,11 +316,9 @@ fn describe_value(
"type" => Value::string("list", head),
"length" => Value::int(vals.len() as i64, head),
"values" => Value::list(vals.into_iter().map(|v|
Ok(compact_primitive_description(
describe_value(v, head, engine_state, options)?
))
compact_primitive_description(describe_value(v, head, engine_state))
)
.collect::<Result<Vec<Value>, ShellError>>()?, head),
.collect(), head),
),
head,
),
@ -394,42 +370,7 @@ fn describe_value(
),
head,
),
Value::LazyRecord { val, .. } => {
let mut record = Record::new();
record.push("type", Value::string("record", head));
record.push("lazy", Value::bool(true, head));
if options.collect_lazyrecords {
let collected = val.collect()?;
if let Value::Record { val, .. } =
describe_value(collected, head, engine_state, options)?
{
let mut val = Record::clone(&val);
for (_k, v) in val.iter_mut() {
*v = compact_primitive_description(describe_value(
std::mem::take(v),
head,
engine_state,
options,
)?);
}
record.push("length", Value::int(val.len() as i64, head));
record.push("columns", Value::record(val, head));
} else {
let cols = val.column_names();
record.push("length", Value::int(cols.len() as i64, head));
}
} else {
let cols = val.column_names();
record.push("length", Value::int(cols.len() as i64, head));
}
Value::record(record, head)
}
})
}
fn metadata_to_value(metadata: Option<Box<PipelineMetadata>>, head: nu_protocol::Span) -> Value {

View File

@ -1,179 +0,0 @@
use nu_engine::{command_prelude::*, eval_block};
use nu_protocol::{debugger::WithoutDebug, engine::Closure, LazyRecord};
use std::{
collections::{hash_map::Entry, HashMap},
sync::{Arc, Mutex},
};
#[derive(Clone)]
pub struct LazyMake;
impl Command for LazyMake {
fn name(&self) -> &str {
"lazy make"
}
fn signature(&self) -> Signature {
Signature::build("lazy make")
.input_output_types(vec![(Type::Nothing, Type::record())])
.required_named(
"columns",
SyntaxShape::List(Box::new(SyntaxShape::String)),
"Closure that gets called when the LazyRecord needs to list the available column names",
Some('c')
)
.required_named(
"get-value",
SyntaxShape::Closure(Some(vec![SyntaxShape::String])),
"Closure to call when a value needs to be produced on demand",
Some('g')
)
.category(Category::Core)
}
fn usage(&self) -> &str {
"Create a lazy record."
}
fn extra_usage(&self) -> &str {
"Lazy records are special records that only evaluate their values once the property is requested.
For example, when printing a lazy record, all of its fields will be collected. But when accessing
a specific property, only it will be evaluated.
Note that this is unrelated to the lazyframes feature bundled with dataframes."
}
fn search_terms(&self) -> Vec<&str> {
vec!["deferred", "record", "procedural"]
}
fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
nu_protocol::report_error_new(
engine_state,
&ShellError::GenericError {
error: "Deprecated command".into(),
msg: "warning: lazy records and the `lazy make` command will be removed in 0.94.0"
.into(),
span: Some(call.head),
help: None,
inner: vec![],
},
);
let span = call.head;
let columns: Vec<Spanned<String>> = call
.get_flag(engine_state, stack, "columns")?
.expect("required flag");
let get_value: Closure = call
.get_flag(engine_state, stack, "get-value")?
.expect("required flag");
let mut unique = HashMap::with_capacity(columns.len());
for col in &columns {
match unique.entry(&col.item) {
Entry::Occupied(entry) => {
return Err(ShellError::ColumnDefinedTwice {
col_name: col.item.clone(),
second_use: col.span,
first_use: *entry.get(),
});
}
Entry::Vacant(entry) => {
entry.insert(col.span);
}
}
}
let stack = stack.clone().reset_out_dest().capture();
Ok(Value::lazy_record(
Box::new(NuLazyRecord {
engine_state: engine_state.clone(),
stack: Arc::new(Mutex::new(stack)),
columns: columns.into_iter().map(|s| s.item).collect(),
get_value,
span,
}),
span,
)
.into_pipeline_data())
}
fn examples(&self) -> Vec<Example> {
vec![
// TODO: Figure out how to "test" these examples, or leave results as None
Example {
description: "Create a lazy record",
example: r#"lazy make --columns ["haskell", "futures", "nushell"] --get-value { |lazything| $lazything + "!" }"#,
result: None,
},
Example {
description: "Test the laziness of lazy records",
example: r#"lazy make --columns ["hello"] --get-value { |key| print $"getting ($key)!"; $key | str upcase }"#,
result: None,
},
]
}
}
#[derive(Clone)]
struct NuLazyRecord {
engine_state: EngineState,
stack: Arc<Mutex<Stack>>,
columns: Vec<String>,
get_value: Closure,
span: Span,
}
impl std::fmt::Debug for NuLazyRecord {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("NuLazyRecord").finish()
}
}
impl<'a> LazyRecord<'a> for NuLazyRecord {
fn column_names(&'a self) -> Vec<&'a str> {
self.columns.iter().map(|column| column.as_str()).collect()
}
fn get_column_value(&self, column: &str) -> Result<Value, ShellError> {
let block = self.engine_state.get_block(self.get_value.block_id);
let mut stack = self.stack.lock().expect("lock must not be poisoned");
let column_value = Value::string(column, self.span);
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
stack.add_var(*var_id, column_value.clone());
}
}
let pipeline_result = eval_block::<WithoutDebug>(
&self.engine_state,
&mut stack,
block,
PipelineData::Value(column_value, None),
);
pipeline_result.map(|data| match data {
PipelineData::Value(value, ..) => value,
// TODO: Proper error handling.
_ => Value::nothing(self.span),
})
}
fn span(&self) -> Span {
self.span
}
fn clone_value(&self, span: Span) -> Value {
Value::lazy_record(Box::new((*self).clone()), span)
}
}

View File

@ -21,7 +21,6 @@ mod hide;
mod hide_env;
mod if_;
mod ignore;
mod lazy_make;
mod let_;
mod loop_;
mod match_;
@ -58,7 +57,6 @@ pub use hide::Hide;
pub use hide_env::HideEnv;
pub use if_::If;
pub use ignore::Ignore;
pub use lazy_make::LazyMake;
pub use let_::Let;
pub use loop_::Loop;
pub use match_::Match;

View File

@ -43,7 +43,6 @@ pub fn create_default_context() -> EngineState {
OverlayList,
OverlayNew,
OverlayHide,
LazyMake,
Let,
Loop,
Match,

View File

@ -306,10 +306,6 @@ impl<'a> std::fmt::Debug for DebuggableValue<'a> {
Value::Custom { val, .. } => {
write!(f, "CustomValue({:?})", val)
}
Value::LazyRecord { val, .. } => {
let rec = val.collect().map_err(|_| std::fmt::Error)?;
write!(f, "LazyRecord({:?})", DebuggableValue(&rec))
}
}
}
}

View File

@ -106,10 +106,9 @@ impl<'a> StyleComputer<'a> {
Value::Binary { .. } => TextStyle::with_style(Left, s),
Value::CellPath { .. } => TextStyle::with_style(Left, s),
Value::Record { .. } | Value::List { .. } => TextStyle::with_style(Left, s),
Value::Closure { .. }
| Value::Custom { .. }
| Value::Error { .. }
| Value::LazyRecord { .. } => TextStyle::basic_left(),
Value::Closure { .. } | Value::Custom { .. } | Value::Error { .. } => {
TextStyle::basic_left()
}
}
}

View File

@ -272,10 +272,6 @@ pub fn debug_string_without_formatting(value: &Value) -> String {
.collect::<Vec<_>>()
.join(" ")
),
Value::LazyRecord { val, .. } => match val.collect() {
Ok(val) => debug_string_without_formatting(&val),
Err(error) => format!("{error:?}"),
},
//TODO: It would be good to drill deeper into closures.
Value::Closure { val, .. } => format!("<Closure {}>", val.block_id),
Value::Nothing { .. } => String::new(),

View File

@ -1,5 +1,4 @@
use nu_engine::command_prelude::*;
use nu_protocol::LazyRecord;
use sysinfo::{MemoryRefreshKind, Pid, ProcessRefreshKind, RefreshKind, System};
const ENV_PATH_SEPARATOR_CHAR: char = {
@ -39,14 +38,10 @@ impl Command for DebugInfo {
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
_call: &Call,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let span = Span::unknown();
let record = LazySystemInfoRecord { span };
Ok(Value::lazy_record(Box::new(record), span).into_pipeline_data())
Ok(all_columns(call.head).into_pipeline_data())
}
fn examples(&self) -> Vec<Example> {
@ -58,93 +53,52 @@ impl Command for DebugInfo {
}
}
#[derive(Debug, Clone)]
struct LazySystemInfoRecord {
span: Span,
}
fn all_columns(span: Span) -> Value {
let rk = RefreshKind::new()
.with_processes(ProcessRefreshKind::everything())
.with_memory(MemoryRefreshKind::everything());
// only get information requested
let sys = System::new_with_specifics(rk);
impl LazySystemInfoRecord {
fn get_column_value_with_system(
&self,
column: &str,
system_option: Option<&System>,
) -> Result<Value, ShellError> {
let pid = Pid::from(std::process::id() as usize);
match column {
"thread_id" => Ok(Value::int(get_thread_id() as i64, self.span)),
"pid" => Ok(Value::int(pid.as_u32() as i64, self.span)),
"ppid" => {
// only get information requested
let system_opt = SystemOpt::from((system_option, || {
RefreshKind::new().with_processes(ProcessRefreshKind::everything())
}));
let system = system_opt.get_system();
// get the process information for the nushell pid
let pinfo = system.process(pid);
Ok(pinfo
let ppid = {
sys.process(pid)
.and_then(|p| p.parent())
.map(|p| Value::int(p.as_u32() as i64, self.span))
.unwrap_or(Value::nothing(self.span)))
}
"system" => {
// only get information requested
let system_opt = SystemOpt::from((system_option, || {
RefreshKind::new().with_memory(MemoryRefreshKind::everything())
}));
.map(|p| Value::int(p.as_u32().into(), span))
.unwrap_or(Value::nothing(span))
};
let system = system_opt.get_system();
Ok(Value::record(
let system = Value::record(
record! {
"total_memory" => Value::filesize(system.total_memory() as i64, self.span),
"free_memory" => Value::filesize(system.free_memory() as i64, self.span),
"used_memory" => Value::filesize(system.used_memory() as i64, self.span),
"available_memory" => Value::filesize(system.available_memory() as i64, self.span),
"total_memory" => Value::filesize(sys.total_memory() as i64, span),
"free_memory" => Value::filesize(sys.free_memory() as i64, span),
"used_memory" => Value::filesize(sys.used_memory() as i64, span),
"available_memory" => Value::filesize(sys.available_memory() as i64, span),
},
self.span,
))
}
"process" => {
// only get information requested
let system_opt = SystemOpt::from((system_option, || {
RefreshKind::new().with_processes(ProcessRefreshKind::everything())
}));
span,
);
let system = system_opt.get_system();
let pinfo = system.process(pid);
let process = if let Some(p) = sys.process(pid) {
let root = if let Some(path) = p.exe().and_then(|p| p.parent()) {
Value::string(path.to_string_lossy().to_string(), span)
} else {
Value::nothing(span)
};
if let Some(p) = pinfo {
Ok(Value::record(
record! {
"memory" => Value::filesize(p.memory() as i64, self.span),
"virtual_memory" => Value::filesize(p.virtual_memory() as i64, self.span),
"status" => Value::string(p.status().to_string(), self.span),
"root" => {
if let Some(path) = p.exe().and_then(|p| p.parent()) {
Value::string(path.to_string_lossy().to_string(), self.span)
let cwd = if let Some(path) = p.cwd() {
Value::string(path.to_string_lossy().to_string(), span)
} else {
Value::nothing(self.span)
}
},
"cwd" => {
if let Some(path) = p.cwd() {
Value::string(path.to_string_lossy().to_string(), self.span)
Value::nothing(span)
};
let exe_path = if let Some(path) = p.exe() {
Value::string(path.to_string_lossy().to_string(), span)
} else {
Value::nothing(self.span)
}
},
"exe_path" => {
if let Some(path)= p.exe() {
Value::string(path.to_string_lossy().to_string(), self.span)
}else{
Value::nothing(self.span)
}
},
"command" => Value::string(p.cmd().join(" "), self.span),
"name" => Value::string(p.name().to_string(), self.span),
"environment" => {
Value::nothing(span)
};
let environment = {
let mut env_rec = Record::new();
for val in p.environ() {
if let Some((key, value)) = val.split_once('=') {
@ -152,7 +106,10 @@ impl LazySystemInfoRecord {
{
#[cfg(target_family = "windows")]
{
key == "Path" || key == "PATHEXT" || key == "PSMODULEPATH" || key == "PSModulePath"
key == "Path"
|| key == "PATHEXT"
|| key == "PSMODULEPATH"
|| key == "PSModulePath"
}
#[cfg(not(target_family = "windows"))]
{
@ -161,104 +118,54 @@ impl LazySystemInfoRecord {
}
};
if is_env_var_a_list {
let items = value.split(ENV_PATH_SEPARATOR_CHAR).map(|r| Value::string(r.to_string(), self.span)).collect::<Vec<_>>();
env_rec.push(key.to_string(), Value::list(items, self.span));
} else if key == "LS_COLORS" { // LS_COLORS is a special case, it's a colon separated list of key=value pairs
let items = value.split(':').map(|r| Value::string(r.to_string(), self.span)).collect::<Vec<_>>();
env_rec.push(key.to_string(), Value::list(items, self.span));
let items = value
.split(ENV_PATH_SEPARATOR_CHAR)
.map(|r| Value::string(r.to_string(), span))
.collect::<Vec<_>>();
env_rec.push(key.to_string(), Value::list(items, span));
} else if key == "LS_COLORS" {
// LS_COLORS is a special case, it's a colon separated list of key=value pairs
let items = value
.split(':')
.map(|r| Value::string(r.to_string(), span))
.collect::<Vec<_>>();
env_rec.push(key.to_string(), Value::list(items, span));
} else {
env_rec.push(key.to_string(), Value::string(value.to_string(), self.span));
env_rec.push(key.to_string(), Value::string(value.to_string(), span));
}
}
}
Value::record(env_rec, self.span)
},
},
self.span,
))
} else {
// If we can't get the process information, just return the system information
// only get information requested
let system_opt = SystemOpt::from((system_option, || {
RefreshKind::new().with_memory(MemoryRefreshKind::everything())
}));
let system = system_opt.get_system();
Value::record(env_rec, span)
};
Ok(Value::record(
Value::record(
record! {
"total_memory" => Value::filesize(system.total_memory() as i64, self.span),
"free_memory" => Value::filesize(system.free_memory() as i64, self.span),
"used_memory" => Value::filesize(system.used_memory() as i64, self.span),
"available_memory" => Value::filesize(system.available_memory() as i64, self.span),
"memory" => Value::filesize(p.memory() as i64, span),
"virtual_memory" => Value::filesize(p.virtual_memory() as i64, span),
"status" => Value::string(p.status().to_string(), span),
"root" => root,
"cwd" => cwd,
"exe_path" => exe_path,
"command" => Value::string(p.cmd().join(" "), span),
"name" => Value::string(p.name(), span),
"environment" => environment,
},
self.span,
))
}
}
_ => Err(ShellError::IncompatibleParametersSingle {
msg: format!("Unknown column: {}", column),
span: self.span,
}),
}
}
}
span,
)
} else {
Value::nothing(span)
};
impl<'a> LazyRecord<'a> for LazySystemInfoRecord {
fn column_names(&'a self) -> Vec<&'a str> {
vec!["thread_id", "pid", "ppid", "process", "system"]
}
fn get_column_value(&self, column: &str) -> Result<Value, ShellError> {
self.get_column_value_with_system(column, None)
}
fn span(&self) -> Span {
self.span
}
fn clone_value(&self, span: Span) -> Value {
Value::lazy_record(Box::new(LazySystemInfoRecord { span }), span)
}
fn collect(&'a self) -> Result<Value, ShellError> {
let rk = RefreshKind::new()
.with_processes(ProcessRefreshKind::everything())
.with_memory(MemoryRefreshKind::everything());
// only get information requested
let system = System::new_with_specifics(rk);
self.column_names()
.into_iter()
.map(|col| {
let val = self.get_column_value_with_system(col, Some(&system))?;
Ok((col.to_owned(), val))
})
.collect::<Result<Record, _>>()
.map(|record| Value::record(record, self.span()))
}
}
enum SystemOpt<'a> {
Ptr(&'a System),
Owned(Box<System>),
}
impl<'a> SystemOpt<'a> {
fn get_system(&'a self) -> &'a System {
match self {
SystemOpt::Ptr(system) => system,
SystemOpt::Owned(system) => system,
}
}
}
impl<'a, F: Fn() -> RefreshKind> From<(Option<&'a System>, F)> for SystemOpt<'a> {
fn from((system_opt, refresh_kind_create): (Option<&'a System>, F)) -> Self {
match system_opt {
Some(system) => SystemOpt::<'a>::Ptr(system),
None => SystemOpt::Owned(Box::new(System::new_with_specifics(refresh_kind_create()))),
}
}
Value::record(
record! {
"thread_id" => Value::int(get_thread_id() as i64, span),
"pid" => Value::int(pid.as_u32().into(), span),
"ppid" => ppid,
"system" => system,
"process" => process,
},
span,
)
}
fn get_thread_id() -> u64 {

View File

@ -105,18 +105,6 @@ fn getcol(
.into_pipeline_data(ctrlc)
.set_metadata(metadata))
}
Value::LazyRecord { val, .. } => {
Ok({
// Unfortunate casualty to LazyRecord's column_names not generating 'static strs
let cols: Vec<_> =
val.column_names().iter().map(|s| s.to_string()).collect();
cols.into_iter()
.map(move |x| Value::string(x, head))
.into_pipeline_data(ctrlc)
.set_metadata(metadata)
})
}
Value::Record { val, .. } => Ok(val
.into_owned()
.into_iter()

View File

@ -533,15 +533,6 @@ fn value_should_be_printed(
Value::Record { val, .. } => {
record_matches_term(val, columns_to_search, filter_config, term, span)
}
Value::LazyRecord { val, .. } => match val.collect() {
Ok(val) => match val {
Value::Record { val, .. } => {
record_matches_term(&val, columns_to_search, filter_config, term, span)
}
_ => false,
},
Err(_) => false,
},
Value::Binary { .. } => false,
});
if invert {

View File

@ -44,12 +44,6 @@ impl Command for Items {
match input {
PipelineData::Empty => Ok(PipelineData::Empty),
PipelineData::Value(value, ..) => {
let value = if let Value::LazyRecord { val, .. } = value {
val.collect()?
} else {
value
};
let span = value.span();
match value {
Value::Record { val, .. } => {

View File

@ -161,20 +161,6 @@ fn values(
.cloned()
.collect::<Vec<_>>()
.into_pipeline_data_with_metadata(metadata, ctrlc)),
Value::LazyRecord { val, .. } => {
let record = match val.collect()? {
Value::Record { val, .. } => val,
_ => Err(ShellError::NushellFailedSpanned {
msg: "`LazyRecord::collect()` promises `Value::Record`".into(),
label: "Violating lazy record found here".into(),
span,
})?,
};
Ok(record
.into_owned()
.into_values()
.into_pipeline_data_with_metadata(metadata, ctrlc))
}
// Propagate errors
Value::Error { error, .. } => Err(*error),
other => Err(ShellError::OnlySupportsThisInputType {

View File

@ -135,10 +135,6 @@ pub fn value_to_json_value(v: &Value) -> Result<nu_json::Value, ShellError> {
}
nu_json::Value::Object(m)
}
Value::LazyRecord { val, .. } => {
let collected = val.collect()?;
value_to_json_value(&collected)?
}
Value::Custom { val, .. } => {
let collected = val.to_base_value(span)?;
value_to_json_value(&collected)?

View File

@ -246,9 +246,6 @@ pub(crate) fn write_value(
Value::Custom { val, .. } => {
write_value(out, &val.to_base_value(span)?, depth)?;
}
Value::LazyRecord { val, .. } => {
write_value(out, &val.collect()?, depth)?;
}
}
Ok(())
}

View File

@ -130,10 +130,6 @@ fn local_into_string(value: Value, separator: &str, config: &Config) -> String {
.map(|(x, y)| format!("{}: {}", x, local_into_string(y, ", ", config)))
.collect::<Vec<_>>()
.join(separator),
Value::LazyRecord { val, .. } => match val.collect() {
Ok(val) => local_into_string(val, separator, config),
Err(error) => format!("{error:?}"),
},
Value::Closure { val, .. } => format!("<Closure {}>", val.block_id),
Value::Nothing { .. } => String::new(),
Value::Error { error, .. } => format!("{error:?}"),

View File

@ -62,10 +62,6 @@ fn helper(engine_state: &EngineState, v: &Value) -> Result<toml::Value, ShellErr
}
toml::Value::Table(m)
}
Value::LazyRecord { val, .. } => {
let collected = val.collect()?;
helper(engine_state, &collected)?
}
Value::List { vals, .. } => toml::Value::Array(toml_list(engine_state, vals)?),
Value::Closure { .. } => {
let code = engine_state.get_span_contents(span);

View File

@ -62,10 +62,6 @@ pub fn value_to_yaml_value(v: &Value) -> Result<serde_yaml::Value, ShellError> {
}
serde_yaml::Value::Mapping(m)
}
Value::LazyRecord { val, .. } => {
let collected = val.collect()?;
value_to_yaml_value(&collected)?
}
Value::List { vals, .. } => {
let mut out = vec![];

View File

@ -1,6 +1,5 @@
use chrono::{DateTime, Local};
use nu_engine::command_prelude::*;
use nu_protocol::LazyRecord;
use std::time::{Duration, UNIX_EPOCH};
use sysinfo::{
Components, CpuRefreshKind, Disks, Networks, System, Users, MINIMUM_CPU_UPDATE_INTERVAL,
@ -32,10 +31,7 @@ impl Command for Sys {
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let span = call.span();
let ret = Value::lazy_record(Box::new(SysResult { span }), span);
Ok(ret.into_pipeline_data())
Ok(all_columns(call.head).into_pipeline_data())
}
fn examples(&self) -> Vec<Example> {
@ -64,36 +60,18 @@ pub struct SysResult {
pub span: Span,
}
impl LazyRecord<'_> for SysResult {
fn column_names(&self) -> Vec<&'static str> {
vec!["host", "cpu", "disks", "mem", "temp", "net"]
}
fn get_column_value(&self, column: &str) -> Result<Value, ShellError> {
let span = self.span;
match column {
"host" => Ok(host(span)),
"cpu" => Ok(cpu(span)),
"disks" => Ok(disks(span)),
"mem" => Ok(mem(span)),
"temp" => Ok(temp(span)),
"net" => Ok(net(span)),
_ => Err(ShellError::LazyRecordAccessFailed {
message: format!("Could not find column '{column}'"),
column_name: column.to_string(),
fn all_columns(span: Span) -> Value {
Value::record(
record! {
"host" => host(span),
"cpu" => cpu(span),
"disks" => disks(span),
"mem" => mem(span),
"temp" => temp(span),
"net" => net(span),
},
span,
}),
}
}
fn span(&self) -> Span {
self.span
}
fn clone_value(&self, span: Span) -> Value {
Value::lazy_record(Box::new((*self).clone()), span)
}
)
}
pub fn trim_cstyle_null(s: String) -> String {

View File

@ -394,10 +394,6 @@ fn handle_table_command(
input.data = PipelineData::Empty;
handle_record(input, cfg, val.into_owned())
}
PipelineData::Value(Value::LazyRecord { val, .. }, ..) => {
input.data = val.collect()?.into_pipeline_data();
handle_table_command(input, cfg)
}
PipelineData::Value(Value::Error { error, .. }, ..) => {
// Propagate this error outward, so that it goes to stderr
// instead of stdout.

View File

@ -98,21 +98,6 @@ fn insert_uses_enumerate_index() {
assert_eq!(actual.out, "[[index, a, b]; [0, 7, 8], [1, 6, 8]]");
}
#[test]
fn insert_support_lazy_record() {
let actual =
nu!(r#"let x = (lazy make -c ["h"] -g {|a| $a | str upcase}); $x | insert a 10 | get a"#);
assert_eq!(actual.out, "10");
}
#[test]
fn lazy_record_test_values() {
let actual = nu!(
r#"lazy make --columns ["haskell", "futures", "nushell"] --get-value { |lazything| $lazything + "!" } | values | length"#
);
assert_eq!(actual.out, "3");
}
#[test]
fn deep_cell_path_creates_all_nested_records() {
let actual = nu!("{a: {}} | insert a.b.c 0 | get a.b.c");

View File

@ -103,13 +103,6 @@ fn update_uses_enumerate_index() {
assert_eq!(actual.out, "[[index, a]; [0, 8], [1, 8]]");
}
#[test]
fn update_support_lazy_record() {
let actual =
nu!(r#"let x = (lazy make -c ["h"] -g {|a| $a | str upcase}); $x | update h 10 | get h"#);
assert_eq!(actual.out, "10");
}
#[test]
fn list_replacement_closure() {
let actual = nu!("[1, 2] | update 1 {|i| $i + 1 } | to nuon");

View File

@ -112,17 +112,6 @@ fn upsert_past_end_of_list_stream() {
.contains("can't insert at index (the next available index is 3)"));
}
#[test]
fn upsert_support_lazy_record() {
let actual =
nu!(r#"let x = (lazy make -c ["h"] -g {|a| $a | str upcase}); $x | upsert h 10 | get h"#);
assert_eq!(actual.out, "10");
let actual =
nu!(r#"let x = (lazy make -c ["h"] -g {|a| $a | str upcase}); $x | upsert aa 10 | get aa"#);
assert_eq!(actual.out, "10");
}
#[test]
fn deep_cell_path_creates_all_nested_records() {
let actual = nu!("{a: {}} | upsert a.b.c 0 | get a.b.c");

View File

@ -112,10 +112,6 @@ pub fn collect_input(value: Value) -> Result<(Vec<String>, Vec<Vec<Value>>)> {
Ok((vec![String::from("")], lines))
}
Value::LazyRecord { val, .. } => {
let materialized = val.collect()?;
collect_input(materialized)
}
Value::Nothing { .. } => Ok((vec![], vec![])),
Value::Custom { val, .. } => {
let materialized = val.to_base_value(span)?;

View File

@ -2,8 +2,6 @@ use nu_protocol::{CustomValue, IntoSpanned, ShellError, Spanned, Value};
/// Do something with all [`CustomValue`]s recursively within a `Value`. This is not limited to
/// plugin custom values.
///
/// `LazyRecord`s will be collected to plain values for completeness.
pub fn with_custom_values_in<E>(
value: &mut Value,
mut f: impl FnMut(Spanned<&mut Box<dyn CustomValue>>) -> Result<(), E>,
@ -18,13 +16,6 @@ where
// Operate on a CustomValue.
f(val.into_spanned(span))
}
// LazyRecord would be a problem for us, since it could return something else the
// next time, and we have to collect it anyway to serialize it. Collect it in place,
// and then use the result
Value::LazyRecord { val, .. } => {
*value = val.collect()?;
Ok(())
}
_ => Ok(()),
}
})
@ -33,31 +24,7 @@ where
#[test]
fn find_custom_values() {
use nu_plugin_protocol::test_util::test_plugin_custom_value;
use nu_protocol::{engine::Closure, record, LazyRecord, Span};
#[derive(Debug, Clone)]
struct Lazy;
impl<'a> LazyRecord<'a> for Lazy {
fn column_names(&'a self) -> Vec<&'a str> {
vec!["custom", "plain"]
}
fn get_column_value(&self, column: &str) -> Result<Value, ShellError> {
Ok(match column {
"custom" => Value::test_custom_value(Box::new(test_plugin_custom_value())),
"plain" => Value::test_int(42),
_ => unimplemented!(),
})
}
fn span(&self) -> Span {
Span::test_data()
}
fn clone_value(&self, span: Span) -> Value {
Value::lazy_record(Box::new(self.clone()), span)
}
}
use nu_protocol::{engine::Closure, record};
let mut cv = Value::test_custom_value(Box::new(test_plugin_custom_value()));
@ -73,7 +40,6 @@ fn find_custom_values() {
captures: vec![(0, cv.clone()), (1, Value::test_string("foo"))]
}
),
"lazy" => Value::test_lazy_record(Box::new(Lazy)),
});
// Do with_custom_values_in, and count the number of custom values found
@ -83,7 +49,7 @@ fn find_custom_values() {
Ok(())
})
.expect("error");
assert_eq!(4, found, "found in value");
assert_eq!(3, found, "found in value");
// Try it on bare custom value too
found = 0;

View File

@ -179,11 +179,6 @@ impl PluginCustomValue {
Ok(())
}
}
// Collect LazyRecord before proceeding
Value::LazyRecord { ref val, .. } => {
*value = val.collect()?;
Ok(())
}
_ => Ok(()),
}
})
@ -205,11 +200,6 @@ impl PluginCustomValue {
Ok(())
}
}
// Collect LazyRecord before proceeding
Value::LazyRecord { ref val, .. } => {
*value = val.collect()?;
Ok(())
}
_ => Ok(()),
}
})
@ -224,11 +214,6 @@ impl PluginCustomValue {
*value = val.to_base_value(span)?;
Ok(())
}
// Collect LazyRecord before proceeding
Value::LazyRecord { ref val, .. } => {
*value = val.collect()?;
Ok(())
}
_ => Ok(()),
}
})

View File

@ -344,9 +344,6 @@ impl PluginTest {
// All equal, and same length
Ok(true)
}
// Must collect lazy records to compare.
(Value::LazyRecord { val: a_val, .. }, _) => self.value_eq(&a_val.collect()?, b),
(_, Value::LazyRecord { val: b_val, .. }) => self.value_eq(a, &b_val.collect()?),
// Fall back to regular eq.
_ => Ok(a == b),
}

View File

@ -381,11 +381,6 @@ pub(crate) fn render_examples(
plugin.custom_value_to_base_value(engine, val.into_spanned(span))?;
Ok::<_, ShellError>(())
}
// Collect LazyRecord before proceeding
Value::LazyRecord { ref val, .. } => {
*value = val.collect()?;
Ok(())
}
_ => Ok(()),
}
})?;

View File

@ -1178,16 +1178,6 @@ pub enum ShellError {
span: Option<Span>,
},
/// An attempt to access a record column failed.
#[error("Access failure: {message}")]
#[diagnostic(code(nu::shell::lazy_record_access_failed))]
LazyRecordAccessFailed {
message: String,
column_name: String,
#[label("Could not access '{column_name}' on this record")]
span: Span,
},
/// Operation interrupted by user
#[error("Operation interrupted by user")]
InterruptedByUser {

View File

@ -1,29 +0,0 @@
use crate::{Record, ShellError, Span, Value};
use std::fmt;
// Trait definition for a lazy record (where columns are evaluated on-demand)
// typetag is needed to make this implement Serialize+Deserialize... even though we should never actually serialize a LazyRecord.
// To serialize a LazyRecord, collect it into a Value::Record with collect() first.
pub trait LazyRecord<'a>: fmt::Debug + Send + Sync {
// All column names
fn column_names(&'a self) -> Vec<&'a str>;
// Get 1 specific column value
fn get_column_value(&self, column: &str) -> Result<Value, ShellError>;
fn span(&self) -> Span;
// Convert the lazy record into a regular Value::Record by collecting all its columns
fn collect(&'a self) -> Result<Value, ShellError> {
self.column_names()
.into_iter()
.map(|col| {
let val = self.get_column_value(col)?;
Ok((col.to_owned(), val))
})
.collect::<Result<Record, _>>()
.map(|record| Value::record(record, self.span()))
}
fn clone_value(&self, span: Span) -> Value;
}

View File

@ -4,7 +4,6 @@ mod filesize;
mod from;
mod from_value;
mod glob;
mod lazy_record;
mod range;
pub mod record;
@ -13,7 +12,6 @@ pub use duration::*;
pub use filesize::*;
pub use from_value::FromValue;
pub use glob::*;
pub use lazy_record::LazyRecord;
pub use range::{FloatRange, IntRange, Range};
pub use record::Record;
@ -164,13 +162,6 @@ pub enum Value {
#[serde(rename = "span")]
internal_span: Span,
},
#[serde(skip)]
LazyRecord {
val: Box<dyn for<'a> LazyRecord<'a>>,
// note: spans are being refactored out of Value
// please use .span() instead of matching this span value
internal_span: Span,
},
}
impl Clone for Value {
@ -212,7 +203,6 @@ impl Clone for Value {
val: val.clone(),
internal_span: *internal_span,
},
Value::LazyRecord { val, internal_span } => val.clone_value(*internal_span),
Value::List {
vals,
internal_span,
@ -672,24 +662,6 @@ impl Value {
}
}
/// Returns a reference to the inner [`LazyRecord`] trait object or an error if this `Value` is not a lazy record
pub fn as_lazy_record(&self) -> Result<&dyn for<'a> LazyRecord<'a>, ShellError> {
if let Value::LazyRecord { val, .. } = self {
Ok(val.as_ref())
} else {
self.cant_convert_to("lazy record")
}
}
/// Unwraps the inner [`LazyRecord`] trait object or returns an error if this `Value` is not a lazy record
pub fn into_lazy_record(self) -> Result<Box<dyn for<'a> LazyRecord<'a>>, ShellError> {
if let Value::LazyRecord { val, .. } = self {
Ok(val)
} else {
self.cant_convert_to("lazy record")
}
}
/// Get the span for the current value
pub fn span(&self) -> Span {
match self {
@ -709,7 +681,6 @@ impl Value {
| Value::Binary { internal_span, .. }
| Value::CellPath { internal_span, .. }
| Value::Custom { internal_span, .. }
| Value::LazyRecord { internal_span, .. }
| Value::Error { internal_span, .. } => *internal_span,
}
}
@ -727,7 +698,6 @@ impl Value {
| Value::String { internal_span, .. }
| Value::Glob { internal_span, .. }
| Value::Record { internal_span, .. }
| Value::LazyRecord { internal_span, .. }
| Value::List { internal_span, .. }
| Value::Closure { internal_span, .. }
| Value::Nothing { internal_span, .. }
@ -784,10 +754,6 @@ impl Value {
None => Type::List(Box::new(Type::Any)),
}
}
Value::LazyRecord { val, .. } => match val.collect() {
Ok(val) => val.get_type(),
Err(..) => Type::Error,
},
Value::Nothing { .. } => Type::Nothing,
Value::Closure { .. } => Type::Closure,
Value::Error { .. } => Type::Error,
@ -893,10 +859,6 @@ impl Value {
.collect::<Vec<_>>()
.join(separator)
),
Value::LazyRecord { val, .. } => val
.collect()
.unwrap_or_else(|err| Value::error(err, span))
.to_expanded_string(separator, config),
Value::Closure { val, .. } => format!("<Closure {}>", val.block_id),
Value::Nothing { .. } => String::new(),
Value::Error { error, .. } => format!("{error:?}"),
@ -919,7 +881,6 @@ impl Value {
/// - "[list {n} items]"
/// - "[record {n} fields]"
pub fn to_abbreviated_string(&self, config: &Config) -> String {
let span = self.span();
match self {
Value::Date { val, .. } => match &config.datetime_table_format {
Some(format) => self.format_datetime(val, format),
@ -945,10 +906,6 @@ impl Value {
val.len(),
if val.len() == 1 { "" } else { "s" }
),
Value::LazyRecord { val, .. } => val
.collect()
.unwrap_or_else(|err| Value::error(err, span))
.to_abbreviated_string(config),
val => val.to_expanded_string(", ", config),
}
}
@ -1087,7 +1044,7 @@ impl Value {
}
// Records (and tables) are the only built-in which support column names,
// so only use this message for them.
Value::Record { .. } | Value::LazyRecord { .. } => {
Value::Record { .. } => {
return Err(ShellError::TypeMismatch {
err_message:"Can't access record values with a row index. Try specifying a column name instead".into(),
span: *origin_span,
@ -1137,32 +1094,6 @@ impl Value {
});
}
}
Value::LazyRecord { val, .. } => {
let columns = val.column_names();
if let Some(col) = columns.iter().rev().find(|&col| {
if insensitive {
col.eq_ignore_case(column_name)
} else {
col == column_name
}
}) {
current = val.get_column_value(col)?;
} else if *optional {
return Ok(Value::nothing(*origin_span)); // short-circuit
} else if let Some(suggestion) = did_you_mean(&columns, column_name) {
return Err(ShellError::DidYouMean {
suggestion,
span: *origin_span,
});
} else {
return Err(ShellError::CantFindColumn {
col_name: column_name.clone(),
span: *origin_span,
src_span: span,
});
}
}
// String access of Lists always means Table access.
// Create a List which contains each matching value for contained
// records in the source list.
@ -1327,11 +1258,6 @@ impl Value {
record.to_mut().push(col_name, new_col);
}
}
Value::LazyRecord { val, .. } => {
// convert to Record first.
*self = val.collect()?;
self.upsert_data_at_cell_path(cell_path, new_val)?;
}
Value::Error { error, .. } => return Err(*error.clone()),
v => {
return Err(ShellError::CantFindColumn {
@ -1443,11 +1369,6 @@ impl Value {
});
}
}
Value::LazyRecord { val, .. } => {
// convert to Record first.
*self = val.collect()?;
self.update_data_at_cell_path(cell_path, new_val)?;
}
Value::Error { error, .. } => return Err(*error.clone()),
v => {
return Err(ShellError::CantFindColumn {
@ -1532,11 +1453,6 @@ impl Value {
}
Ok(())
}
Value::LazyRecord { val, .. } => {
// convert to Record first.
*self = val.collect()?;
self.remove_data_at_cell_path(cell_path)
}
v => Err(ShellError::CantFindColumn {
col_name: col_name.clone(),
span: *span,
@ -1616,11 +1532,6 @@ impl Value {
}
Ok(())
}
Value::LazyRecord { val, .. } => {
// convert to Record first.
*self = val.collect()?;
self.remove_data_at_cell_path(cell_path)
}
v => Err(ShellError::CantFindColumn {
col_name: col_name.clone(),
span: *span,
@ -1739,11 +1650,6 @@ impl Value {
record.to_mut().push(col_name, new_col);
}
}
Value::LazyRecord { val, .. } => {
// convert to Record first.
*self = val.collect()?;
self.insert_data_at_cell_path(cell_path, new_val, v_span)?;
}
other => {
return Err(ShellError::UnsupportedInput {
msg: "table or record".into(),
@ -1797,8 +1703,6 @@ impl Value {
///
/// If the closure returns `Err`, the traversal will stop.
///
/// If collecting lazy records to check them as well is desirable, make sure to do it in your
/// closure. The traversal continues on whatever modifications you make during the closure.
/// Captures of closure values are currently visited, as they are values owned by the closure.
pub fn recurse_mut<E>(
&mut self,
@ -1837,7 +1741,7 @@ impl Value {
| Value::Binary { .. }
| Value::CellPath { .. } => Ok(()),
// These could potentially contain values, but we expect the closure to handle them
Value::LazyRecord { .. } | Value::Custom { .. } => Ok(()),
Value::Custom { .. } => Ok(()),
}
}
@ -1998,13 +1902,6 @@ impl Value {
}
}
pub fn lazy_record(val: Box<dyn for<'a> LazyRecord<'a>>, span: Span) -> Value {
Value::LazyRecord {
val,
internal_span: span,
}
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_bool(val: bool) -> Value {
@ -2101,17 +1998,11 @@ impl Value {
Value::custom(val, Span::test_data())
}
/// Note: Only use this for test data, *not* live data, as it will point into unknown source
/// when used in errors.
pub fn test_lazy_record(val: Box<dyn for<'a> LazyRecord<'a>>) -> Value {
Value::lazy_record(val, Span::test_data())
}
/// Note: Only use this for test data, *not* live data,
/// as it will point into unknown source when used in errors.
///
/// Returns a `Vec` containing one of each value case (`Value::Int`, `Value::String`, etc.)
/// except for `Value::LazyRecord` and `Value::CustomValue`.
/// except for `Value::CustomValue`.
pub fn test_values() -> Vec<Value> {
vec![
Value::test_bool(false),
@ -2127,7 +2018,6 @@ impl Value {
Value::test_float(0.0),
Value::test_string(String::new()),
Value::test_record(Record::new()),
// Value::test_lazy_record(Box::new(todo!())),
Value::test_list(Vec::new()),
Value::test_closure(Closure {
block_id: 0,
@ -2181,7 +2071,6 @@ impl PartialOrd for Value {
Value::String { .. } => Some(Ordering::Less),
Value::Glob { .. } => Some(Ordering::Less),
Value::Record { .. } => Some(Ordering::Less),
Value::LazyRecord { .. } => Some(Ordering::Less),
Value::List { .. } => Some(Ordering::Less),
Value::Closure { .. } => Some(Ordering::Less),
Value::Nothing { .. } => Some(Ordering::Less),
@ -2201,7 +2090,6 @@ impl PartialOrd for Value {
Value::String { .. } => Some(Ordering::Less),
Value::Glob { .. } => Some(Ordering::Less),
Value::Record { .. } => Some(Ordering::Less),
Value::LazyRecord { .. } => Some(Ordering::Less),
Value::List { .. } => Some(Ordering::Less),
Value::Closure { .. } => Some(Ordering::Less),
Value::Nothing { .. } => Some(Ordering::Less),
@ -2221,7 +2109,6 @@ impl PartialOrd for Value {
Value::String { .. } => Some(Ordering::Less),
Value::Glob { .. } => Some(Ordering::Less),
Value::Record { .. } => Some(Ordering::Less),
Value::LazyRecord { .. } => Some(Ordering::Less),
Value::List { .. } => Some(Ordering::Less),
Value::Closure { .. } => Some(Ordering::Less),
Value::Nothing { .. } => Some(Ordering::Less),
@ -2241,7 +2128,6 @@ impl PartialOrd for Value {
Value::String { .. } => Some(Ordering::Less),
Value::Glob { .. } => Some(Ordering::Less),
Value::Record { .. } => Some(Ordering::Less),
Value::LazyRecord { .. } => Some(Ordering::Less),
Value::List { .. } => Some(Ordering::Less),
Value::Closure { .. } => Some(Ordering::Less),
Value::Nothing { .. } => Some(Ordering::Less),
@ -2261,7 +2147,6 @@ impl PartialOrd for Value {
Value::String { .. } => Some(Ordering::Less),
Value::Glob { .. } => Some(Ordering::Less),
Value::Record { .. } => Some(Ordering::Less),
Value::LazyRecord { .. } => Some(Ordering::Less),
Value::List { .. } => Some(Ordering::Less),
Value::Closure { .. } => Some(Ordering::Less),
Value::Nothing { .. } => Some(Ordering::Less),
@ -2281,7 +2166,6 @@ impl PartialOrd for Value {
Value::String { .. } => Some(Ordering::Less),
Value::Glob { .. } => Some(Ordering::Less),
Value::Record { .. } => Some(Ordering::Less),
Value::LazyRecord { .. } => Some(Ordering::Less),
Value::List { .. } => Some(Ordering::Less),
Value::Closure { .. } => Some(Ordering::Less),
Value::Nothing { .. } => Some(Ordering::Less),
@ -2301,7 +2185,6 @@ impl PartialOrd for Value {
Value::String { .. } => Some(Ordering::Less),
Value::Glob { .. } => Some(Ordering::Less),
Value::Record { .. } => Some(Ordering::Less),
Value::LazyRecord { .. } => Some(Ordering::Less),
Value::List { .. } => Some(Ordering::Less),
Value::Closure { .. } => Some(Ordering::Less),
Value::Nothing { .. } => Some(Ordering::Less),
@ -2321,7 +2204,6 @@ impl PartialOrd for Value {
Value::String { val: rhs, .. } => lhs.partial_cmp(rhs),
Value::Glob { val: rhs, .. } => lhs.partial_cmp(rhs),
Value::Record { .. } => Some(Ordering::Less),
Value::LazyRecord { .. } => Some(Ordering::Less),
Value::List { .. } => Some(Ordering::Less),
Value::Closure { .. } => Some(Ordering::Less),
Value::Nothing { .. } => Some(Ordering::Less),
@ -2341,7 +2223,6 @@ impl PartialOrd for Value {
Value::String { val: rhs, .. } => lhs.partial_cmp(rhs),
Value::Glob { val: rhs, .. } => lhs.partial_cmp(rhs),
Value::Record { .. } => Some(Ordering::Less),
Value::LazyRecord { .. } => Some(Ordering::Less),
Value::List { .. } => Some(Ordering::Less),
Value::Closure { .. } => Some(Ordering::Less),
Value::Nothing { .. } => Some(Ordering::Less),
@ -2387,13 +2268,6 @@ impl PartialOrd for Value {
// that the shorter sequence is less than the longer one
lhs.len().partial_cmp(&rhs.len())
}
Value::LazyRecord { val, .. } => {
if let Ok(rhs) = val.collect() {
self.partial_cmp(&rhs)
} else {
None
}
}
Value::List { .. } => Some(Ordering::Less),
Value::Closure { .. } => Some(Ordering::Less),
Value::Nothing { .. } => Some(Ordering::Less),
@ -2413,7 +2287,6 @@ impl PartialOrd for Value {
Value::String { .. } => Some(Ordering::Greater),
Value::Glob { .. } => Some(Ordering::Greater),
Value::Record { .. } => Some(Ordering::Greater),
Value::LazyRecord { .. } => Some(Ordering::Greater),
Value::List { vals: rhs, .. } => lhs.partial_cmp(rhs),
Value::Closure { .. } => Some(Ordering::Less),
Value::Nothing { .. } => Some(Ordering::Less),
@ -2433,7 +2306,6 @@ impl PartialOrd for Value {
Value::String { .. } => Some(Ordering::Greater),
Value::Glob { .. } => Some(Ordering::Greater),
Value::Record { .. } => Some(Ordering::Greater),
Value::LazyRecord { .. } => Some(Ordering::Greater),
Value::List { .. } => Some(Ordering::Greater),
Value::Closure { val: rhs, .. } => lhs.block_id.partial_cmp(&rhs.block_id),
Value::Nothing { .. } => Some(Ordering::Less),
@ -2453,7 +2325,6 @@ impl PartialOrd for Value {
Value::String { .. } => Some(Ordering::Greater),
Value::Glob { .. } => Some(Ordering::Greater),
Value::Record { .. } => Some(Ordering::Greater),
Value::LazyRecord { .. } => Some(Ordering::Greater),
Value::List { .. } => Some(Ordering::Greater),
Value::Closure { .. } => Some(Ordering::Greater),
Value::Nothing { .. } => Some(Ordering::Equal),
@ -2473,7 +2344,6 @@ impl PartialOrd for Value {
Value::String { .. } => Some(Ordering::Greater),
Value::Glob { .. } => Some(Ordering::Greater),
Value::Record { .. } => Some(Ordering::Greater),
Value::LazyRecord { .. } => Some(Ordering::Greater),
Value::List { .. } => Some(Ordering::Greater),
Value::Closure { .. } => Some(Ordering::Greater),
Value::Nothing { .. } => Some(Ordering::Greater),
@ -2493,7 +2363,6 @@ impl PartialOrd for Value {
Value::String { .. } => Some(Ordering::Greater),
Value::Glob { .. } => Some(Ordering::Greater),
Value::Record { .. } => Some(Ordering::Greater),
Value::LazyRecord { .. } => Some(Ordering::Greater),
Value::List { .. } => Some(Ordering::Greater),
Value::Closure { .. } => Some(Ordering::Greater),
Value::Nothing { .. } => Some(Ordering::Greater),
@ -2513,7 +2382,6 @@ impl PartialOrd for Value {
Value::String { .. } => Some(Ordering::Greater),
Value::Glob { .. } => Some(Ordering::Greater),
Value::Record { .. } => Some(Ordering::Greater),
Value::LazyRecord { .. } => Some(Ordering::Greater),
Value::List { .. } => Some(Ordering::Greater),
Value::Closure { .. } => Some(Ordering::Greater),
Value::Nothing { .. } => Some(Ordering::Greater),
@ -2523,13 +2391,6 @@ impl PartialOrd for Value {
Value::Custom { .. } => Some(Ordering::Less),
},
(Value::Custom { val: lhs, .. }, rhs) => lhs.partial_cmp(rhs),
(Value::LazyRecord { val, .. }, rhs) => {
if let Ok(val) = val.collect() {
val.partial_cmp(rhs)
} else {
None
}
}
}
}
}

View File

@ -221,10 +221,6 @@ fn value_to_string(
collection.join(&format!(",{sep}{nl}"))
))
}
Value::LazyRecord { val, .. } => {
let collected = val.collect()?;
value_to_string(&collected, span, depth + 1, indent)
}
// All strings outside data structures are quoted because they are in 'command position'
// (could be mistaken for commands by the Nu parser)
Value::String { val, .. } => Ok(escape_quote_string(val)),