refactor(tvix/rm): introduce helper for AttrSet Entry API

There are multiple points where an insertion needs to be done into an
attribute set, but copying the key or checking for presence before
insertion should be avoided

As that is a little bit noisy, it's been factored out into a helper
function in this commit.

Change-Id: Ibcb054ebeb25a1236c06c812f47c8e74180d4fc9
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6107
Tested-by: BuildkiteCI
Reviewed-by: grfn <grfn@gws.fyi>
This commit is contained in:
Vincent Ambo 2022-08-10 15:49:41 +03:00 committed by tazjin
parent 295d6e1d59
commit 52736a1dbc

View file

@ -234,12 +234,7 @@ impl VM {
// //
let key = self.pop(); let key = self.pop();
match key { match key {
Value::String(ks) => { Value::String(ks) => set_attr(&mut attrs, ks, value)?,
// TODO(tazjin): try_insert (rust#82766) or entry API
if attrs.insert(ks.clone(), value).is_some() {
return Err(Error::DuplicateAttrsKey { key: ks.0 });
}
}
Value::AttrPath(mut path) => { Value::AttrPath(mut path) => {
set_nested_attr( set_nested_attr(
@ -299,6 +294,29 @@ pub enum NumberPair {
Integer(i64, i64), Integer(i64, i64),
} }
// Set an attribute on an in-construction attribute set, while
// checking against duplicate key.s
fn set_attr(
attrs: &mut BTreeMap<NixString, Value>,
key: NixString,
value: Value,
) -> EvalResult<()> {
let entry = attrs.entry(key);
match entry {
std::collections::btree_map::Entry::Occupied(entry) => {
return Err(Error::DuplicateAttrsKey {
key: entry.key().0.clone(),
})
}
std::collections::btree_map::Entry::Vacant(entry) => {
entry.insert(value);
return Ok(());
}
};
}
// Set a nested attribute inside of an attribute set, throwing a // Set a nested attribute inside of an attribute set, throwing a
// duplicate key error if a non-hashmap entry already exists on the // duplicate key error if a non-hashmap entry already exists on the
// path. // path.
@ -311,25 +329,14 @@ fn set_nested_attr(
mut path: Vec<NixString>, mut path: Vec<NixString>,
value: Value, value: Value,
) -> EvalResult<()> { ) -> EvalResult<()> {
let entry = attrs.entry(key);
// If there is no next key we are at the point where we // If there is no next key we are at the point where we
// should insert the value itself. // should insert the value itself.
if path.is_empty() { if path.is_empty() {
match entry { return set_attr(attrs, key, value);
std::collections::btree_map::Entry::Occupied(entry) => {
return Err(Error::DuplicateAttrsKey {
key: entry.key().0.clone(),
})
}
std::collections::btree_map::Entry::Vacant(entry) => {
entry.insert(value);
return Ok(());
}
};
} }
let entry = attrs.entry(key);
// If there is not we go one step further down, in which case we // If there is not we go one step further down, in which case we
// need to ensure that there either is no entry, or the existing // need to ensure that there either is no entry, or the existing
// entry is a hashmap into which to insert the next value. // entry is a hashmap into which to insert the next value.