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

Code before:
                        .clone();
                }
            } else {
                record.push(
                    col.clone(),
                    calculated_value
                        .as_ref()
                        .unwrap_or(&default_value.item)
                        .clone(),
                );
            }
        }
    }
    Ok(Value::record(record.clone(), Span::unknown()).into_pipeline_data())
}

fn default(
    engine_state: &EngineState,
    stack: &mut Stack,
    call: &Call,
    input: PipelineData,
    default_when_empty: bool,
) -> Result<PipelineData, ShellError> {
    let input_span = input.span().unwrap_or_else(Span::unknown);
    let metadata = input.metadata();
    let default_value: Spanned<Value> = call.req(engine_state, stack, 0)?;
    let columns: Vec<String> = call.rest(engine_state, stack, 1)?;

    // If user supplies columns, check if input is a record or list of records
    // and set the default value for the specified record columns
    if !columns.is_empty() {
        // Single record arm
        if matches!(input, PipelineData::Value(Value::Record { .. }, _)) {
            let Value::Record {
                val: ref mut record,
                ..
            } = input.into_value(input_span)?
            else {
                unreachable!()
            };
            let record = record.to_mut();
            default_record_columns(
                record,
                default_value,
                columns.as_slice(),
                default_when_empty,
                engine_state,
                stack,
                &mut None,
            )
            .map(|x| x.set_metadata(metadata))

Review comment (suggestion):
Values already have an internal span, there's no need to use `Spanned` with `Value`

Code after:
        } else {
            Err(ShellError::PipelineMismatch {
                exp_input_type: "record, table".to_string(),
                dst_span: input_span,
                src_span: input_span,
            })
        }
    // Otherwise, if no column name is given, check if value is null
    // or an empty string, list, or record when --empty is passed
    } else if input.is_nothing()
        || (default_when_empty
            && matches!(input, PipelineData::Value(ref value, _) if value.is_empty()))
    {
        default_value.pipeline_data()
    } else if default_when_empty && matches!(input, PipelineData::ListStream(..)) {
        let PipelineData::ListStream(ls, metadata) = input else {
            unreachable!()
        };
        let span = ls.span();
        let mut stream = ls.into_inner().peekable();
        if stream.peek().is_none() {
            return default_value.pipeline_data();
        }

        // stream's internal state already preserves the original signals config, so if this
        // Signals::empty list stream gets interrupted it will be caught by the underlying iterator
        let ls = ListStream::new(stream, span, Signals::empty());
        Ok(PipelineData::ListStream(ls, metadata))
    // Otherwise, return the input as is
    } else {
        Ok(input)
    }
}

/// A wrapper around the default value to handle closures and caching values
enum DefaultValue {
    Uncalculated(Spanned<ClosureEval>),
    Calculated(Value),
}

impl DefaultValue {
    fn new(engine_state: &EngineState, stack: &Stack, value: Value) -> Self {
        let span = value.span();
        match value {
            Value::Closure { val, .. } => {
                let closure_eval = ClosureEval::new(engine_state, stack, *val);
                DefaultValue::Uncalculated(closure_eval.into_spanned(span))
            }
            _ => DefaultValue::Calculated(value),
        }
    }