Repository: nushell/nushell
File: crates/nu-protocol/src/value/record.rs (Rust)

Code before:
        }
    }

    pub fn get_mut(self, col: impl AsRef<str>) -> Option<&'a mut Value> {
        let idx = self.shared().index_of(col)?;
        let (_, value) = self.record.get_index_mut(idx)?;
        Some(value)
    }

    pub fn remove(&mut self, col: impl AsRef<str>) -> Option<Value> {
        let idx = self.shared().index_of(col)?;
        let (_, val) = self.record.inner.remove(idx);
        Some(val)
    }
}

impl Record {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn with_capacity(capacity: usize) -> Self {
        Self {
            inner: Vec::with_capacity(capacity),
        }
    }

    pub fn cased(&self, casing: Casing) -> CasedRecord<&Record> {
        CasedRecord {
            record: self,
            casing,
        }
    }

    pub fn cased_mut(&mut self, casing: Casing) -> CasedRecord<&mut Record> {
        CasedRecord {
            record: self,
            casing,
        }
    }

    /// Create a [`Record`] from a `Vec` of columns and a `Vec` of [`Value`]s
    ///
    /// Returns an error if `cols` and `vals` have different lengths.
    ///
    /// For perf reasons, this will not validate the rest of the record assumptions:
    /// - unique keys
    pub fn from_raw_cols_vals(
        cols: Vec<String>,
        vals: Vec<Value>,
        input_span: Span,

Review comment (security):
Do we need additional logic for the case-insensitive `insert` to replicate the semantics we have or want for that.

Assume:
```rust
let mut record = record!["Foo": t1, "foo": t2];
record.case_insensitive().insert("foo", t3);
```

Would replace the value t1 but leave the `foo` key untouched. Bit surprising for

What should we do. `Record` semantically allows any string key and preserves order.

For environment variables we use case-preserving semantics like on Windows. i.e. the first casing wins all future editing operations preserve. (here `CasedRecord<CaseInsensitive>` works as expected)

What is quite dubious in its behavior is switching between the different `CasedRecord` variants or `DynCasedRecord`.

In an ideal world am inclined to say we should disallow the `!` cell paths for the `upsert` family if we don't want headaches and only allow it for reading operations.

Code after:
    pub fn get_mut(&mut self, col: impl AsRef<str>) -> Option<&mut Value> {
        let index = self.index_of(col.as_ref())?;
        Some(self.0.get_index_mut(index)?.1)
    }

    /// Remove single value by key and return it
    pub fn remove(&mut self, col: impl AsRef<str>) -> Option<Value> {
        let index = self.index_of(col.as_ref())?;
        Some(self.0.remove_index(index))
    }

    /// Insert into the record, replacing preexisting value if found.
    ///
    /// Returns `Some(previous_value)` if found. Else `None`
    pub fn insert<K>(&mut self, col: K, val: Value) -> Option<Value>
    where
        K: AsRef<str> + Into<String>,
    {
        if let Some(curr_val) = self.get_mut(col.as_ref()) {
            Some(std::mem::replace(curr_val, val))
        } else {
            self.0.push(col, val);
            None
        }
    }
}

impl<'a> WrapCased for &'a Record {
    type Wrapper<S: CaseSensitivity> = &'a CasedRecord<S>;

    #[inline]
    fn case_sensitive(self) -> Self::Wrapper<CaseSensitive> {
        CasedRecord::<CaseSensitive>::from_record(self)
    }

    #[inline]
    fn case_insensitive(self) -> Self::Wrapper<CaseInsensitive> {
        CasedRecord::<CaseInsensitive>::from_record(self)
    }
}

impl<'a> WrapCased for &'a mut Record {
    type Wrapper<S: CaseSensitivity> = &'a mut CasedRecord<S>;

    #[inline]
    fn case_sensitive(self) -> Self::Wrapper<CaseSensitive> {
        CasedRecord::<CaseSensitive>::from_record_mut(self)
    }

    #[inline]
    fn case_insensitive(self) -> Self::Wrapper<CaseInsensitive> {