From 52736a1dbcedcab12e13ccf8a0d02a4b0db57cb1 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Wed, 10 Aug 2022 15:49:41 +0300 Subject: 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 --- tvix/eval/src/vm.rs | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs index b81281cf51..90f5f45f61 100644 --- a/tvix/eval/src/vm.rs +++ b/tvix/eval/src/vm.rs @@ -234,12 +234,7 @@ impl VM { // let key = self.pop(); match key { - Value::String(ks) => { - // 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::String(ks) => set_attr(&mut attrs, ks, value)?, Value::AttrPath(mut path) => { set_nested_attr( @@ -299,6 +294,29 @@ pub enum NumberPair { Integer(i64, i64), } +// Set an attribute on an in-construction attribute set, while +// checking against duplicate key.s +fn set_attr( + attrs: &mut BTreeMap, + 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 // duplicate key error if a non-hashmap entry already exists on the // path. @@ -311,25 +329,14 @@ fn set_nested_attr( mut path: Vec, value: Value, ) -> EvalResult<()> { - let entry = attrs.entry(key); - // If there is no next key we are at the point where we // should insert the value itself. if path.is_empty() { - 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(()); - } - }; + return set_attr(attrs, key, value); } + let entry = attrs.entry(key); + // 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 // entry is a hashmap into which to insert the next value. -- cgit 1.4.1