--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs @@ -2,14 +2,14 @@ error::Error::*, evaluate::operator::{evaluate_add_op, evaluate_binary_op_special, evaluate_unary_op}, push, throw, with_state, ArrValue, Bindable, Context, ContextCreator, FuncDesc, FuncVal, - FutureWrapper, LazyBinding, LazyVal, LazyValValue, ObjMember, ObjValue, ObjectAssertion, + FutureWrapper, LazyBinding, LazyVal, LazyValValue, ObjValue, ObjValueBuilder, ObjectAssertion, Result, Val, }; use jrsonnet_gc::{Gc, Trace}; use jrsonnet_interner::IStr; use jrsonnet_parser::{ ArgsDesc, AssertStmt, BindSpec, CompSpec, Expr, ExprLocation, FieldMember, ForSpecData, - IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc, Visibility, + IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc, }; use jrsonnet_types::ValType; use rustc_hash::{FxHashMap, FxHasher}; @@ -254,8 +254,7 @@ new_bindings.fill(bindings); } - let mut new_members = FxHashMap::default(); - let mut assertions: Vec> = Vec::new(); + let mut builder = ObjValueBuilder::new(); for member in members.iter() { match member { Member::Field(FieldMember { @@ -291,19 +290,16 @@ )?)) } } - new_members.insert( - name.clone(), - ObjMember { - add: *plus, - visibility: *visibility, - invoke: LazyBinding::Bindable(Gc::new(Box::new(ObjMemberBinding { - context_creator: context_creator.clone(), - value: value.clone(), - name, - }))), - location: value.1.clone(), - }, - ); + builder + .member(name.clone()) + .with_add(*plus) + .with_visibility(*visibility) + .with_location(value.1.clone()) + .bindable(Box::new(ObjMemberBinding { + context_creator: context_creator.clone(), + value: value.clone(), + name, + })); } Member::Field(FieldMember { name, @@ -338,20 +334,16 @@ ))) } } - new_members.insert( - name.clone(), - ObjMember { - add: false, - visibility: Visibility::Hidden, - invoke: LazyBinding::Bindable(Gc::new(Box::new(ObjMemberBinding { - context_creator: context_creator.clone(), - value: value.clone(), - params: params.clone(), - name, - }))), - location: value.1.clone(), - }, - ); + builder + .member(name.clone()) + .hide() + .with_location(value.1.clone()) + .binding(LazyBinding::Bindable(Gc::new(Box::new(ObjMemberBinding { + context_creator: context_creator.clone(), + value: value.clone(), + params: params.clone(), + name, + })))); } Member::BindStmt(_) => {} Member::AssertStmt(stmt) => { @@ -371,14 +363,14 @@ evaluate_assert(ctx, &self.assert) } } - assertions.push(Box::new(ObjectAssert { + builder.assert(Box::new(ObjectAssert { context_creator: context_creator.clone(), assert: stmt.clone(), })); } } } - let this = ObjValue::new(None, Gc::new(new_members), Gc::new(assertions)); + let this = builder.build(); future_this.fill(this.clone()); Ok(this) } @@ -388,7 +380,7 @@ ObjBody::MemberList(members) => evaluate_member_list_object(context, members)?, ObjBody::ObjComp(obj) => { let future_this = FutureWrapper::new(); - let mut new_members = FxHashMap::default(); + let mut builder = ObjValueBuilder::new(); evaluate_comp(context.clone(), &obj.compspecs, &mut |ctx| { let new_bindings = FutureWrapper::new(); let context_creator = ContextCreator(context.clone(), new_bindings.clone()); @@ -435,18 +427,13 @@ )?)) } } - new_members.insert( - n, - ObjMember { - add: false, - visibility: Visibility::Normal, - invoke: LazyBinding::Bindable(Gc::new(Box::new(ObjCompBinding { - context: ctx, - value: obj.value.clone(), - }))), - location: obj.value.1.clone(), - }, - ); + builder + .member(n) + .with_location(obj.value.1.clone()) + .bindable(Box::new(ObjCompBinding { + context: ctx, + value: obj.value.clone(), + })); } v => throw!(FieldMustBeStringGot(v.value_type())), } @@ -454,7 +441,7 @@ Ok(()) })?; - let this = ObjValue::new(None, Gc::new(new_members), Gc::new(Vec::new())); + let this = builder.build(); future_this.fill(this.clone()); this } --- a/crates/jrsonnet-evaluator/src/integrations/serde.rs +++ b/crates/jrsonnet-evaluator/src/integrations/serde.rs @@ -1,16 +1,9 @@ use crate::{ error::{Error::*, LocError, Result}, - throw, LazyBinding, LazyVal, ObjMember, ObjValue, Val, + throw, ObjValueBuilder, Val, }; -use jrsonnet_gc::Gc; -use jrsonnet_parser::Visibility; -use rustc_hash::FxHasher; use serde_json::{Map, Number, Value}; -use std::{ - collections::HashMap, - convert::{TryFrom, TryInto}, - hash::BuildHasherDefault, -}; +use std::convert::{TryFrom, TryInto}; impl TryFrom<&Val> for Value { type Error = LocError; @@ -54,29 +47,18 @@ Value::Number(n) => Self::Num(n.as_f64().expect("as f64")), Value::String(s) => Self::Str((s as &str).into()), Value::Array(a) => { - let mut out = Vec::with_capacity(a.len()); + let mut out: Vec = Vec::with_capacity(a.len()); for v in a { - out.push(LazyVal::new_resolved(v.into())); + out.push(v.into()); } Self::Arr(out.into()) } Value::Object(o) => { - let mut entries = HashMap::with_capacity_and_hasher( - o.len(), - BuildHasherDefault::::default(), - ); + let mut builder = ObjValueBuilder::with_capacity(o.len()); for (k, v) in o { - entries.insert( - (k as &str).into(), - ObjMember { - add: false, - visibility: Visibility::Normal, - invoke: LazyBinding::Bound(LazyVal::new_resolved(v.into())), - location: None, - }, - ); + builder.member((k as &str).into()).value(v.into()); } - Self::Obj(ObjValue::new(None, Gc::new(entries), Gc::new(Vec::new()))) + Val::Obj(builder.build()) } } } --- a/crates/jrsonnet-evaluator/src/obj.rs +++ b/crates/jrsonnet-evaluator/src/obj.rs @@ -1,9 +1,10 @@ use crate::operator::evaluate_add_op; -use crate::{LazyBinding, Result, Val}; +use crate::{Bindable, LazyBinding, LazyVal, Result, Val}; use jrsonnet_gc::{Gc, GcCell, Trace}; use jrsonnet_interner::IStr; use jrsonnet_parser::{ExprLocation, Visibility}; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; +use std::collections::HashMap; use std::hash::{Hash, Hasher}; use std::{fmt::Debug, hash::BuildHasherDefault}; @@ -274,3 +275,98 @@ hasher.write_usize(&*self.0 as *const _ as usize) } } + +pub struct ObjValueBuilder { + super_obj: Option, + map: FxHashMap, + assertions: Vec>, +} +impl ObjValueBuilder { + pub fn new() -> Self { + Self::with_capacity(0) + } + pub fn with_capacity(capacity: usize) -> Self { + Self { + super_obj: None, + map: HashMap::with_capacity_and_hasher( + capacity, + BuildHasherDefault::::default(), + ), + assertions: Vec::new(), + } + } + pub fn reserve_asserts(&mut self, capacity: usize) -> &mut Self { + self.assertions.reserve_exact(capacity); + self + } + pub fn with_super(&mut self, super_obj: ObjValue) -> &mut Self { + self.super_obj = Some(super_obj); + self + } + + pub fn assert(&mut self, assertion: Box) -> &mut Self { + self.assertions.push(assertion); + self + } + pub fn member(&mut self, name: IStr) -> ObjMemberBuilder { + ObjMemberBuilder { + value: self, + name, + add: false, + visibility: Visibility::Normal, + location: None, + } + } + + pub fn build(self) -> ObjValue { + ObjValue::new(self.super_obj, Gc::new(self.map), Gc::new(self.assertions)) + } +} + +#[must_use = "value not added unless binding() was called"] +pub struct ObjMemberBuilder<'v> { + value: &'v mut ObjValueBuilder, + name: IStr, + add: bool, + visibility: Visibility, + location: Option, +} + +impl<'v> ObjMemberBuilder<'v> { + pub fn with_add(mut self, add: bool) -> Self { + self.add = add; + self + } + pub fn add(self) -> Self { + self.with_add(true) + } + pub fn with_visibility(mut self, visibility: Visibility) -> Self { + self.visibility = visibility; + self + } + pub fn hide(self) -> Self { + self.with_visibility(Visibility::Hidden) + } + pub fn with_location(mut self, location: Option) -> Self { + self.location = location; + self + } + pub fn value(self, value: Val) -> &'v mut ObjValueBuilder { + self.binding(LazyBinding::Bound(LazyVal::new_resolved(value))) + } + pub fn bindable(self, bindable: Box) -> &'v mut ObjValueBuilder { + self.binding(LazyBinding::Bindable(Gc::new(bindable))) + } + pub fn binding(self, binding: LazyBinding) -> &'v mut ObjValueBuilder { + self.value.map.insert( + self.name, + ObjMember { + add: self.add, + visibility: self.visibility, + invoke: binding, + location: self.location, + }, + ); + self.value + } +}