git.delta.rocks / jrsonnet / refs/commits / f047fb133353

difftreelog

refactor object builder

Yaroslav Bolyukin2021-07-04parent: #f38d264.patch.diff
in: master

3 files changed

modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
2 error::Error::*,2 error::Error::*,
3 evaluate::operator::{evaluate_add_op, evaluate_binary_op_special, evaluate_unary_op},3 evaluate::operator::{evaluate_add_op, evaluate_binary_op_special, evaluate_unary_op},
4 push, throw, with_state, ArrValue, Bindable, Context, ContextCreator, FuncDesc, FuncVal,4 push, throw, with_state, ArrValue, Bindable, Context, ContextCreator, FuncDesc, FuncVal,
5 FutureWrapper, LazyBinding, LazyVal, LazyValValue, ObjMember, ObjValue, ObjectAssertion,5 FutureWrapper, LazyBinding, LazyVal, LazyValValue, ObjValue, ObjValueBuilder, ObjectAssertion,
6 Result, Val,6 Result, Val,
7};7};
8use jrsonnet_gc::{Gc, Trace};8use jrsonnet_gc::{Gc, Trace};
9use jrsonnet_interner::IStr;9use jrsonnet_interner::IStr;
10use jrsonnet_parser::{10use jrsonnet_parser::{
11 ArgsDesc, AssertStmt, BindSpec, CompSpec, Expr, ExprLocation, FieldMember, ForSpecData,11 ArgsDesc, AssertStmt, BindSpec, CompSpec, Expr, ExprLocation, FieldMember, ForSpecData,
12 IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc, Visibility,12 IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc,
13};13};
14use jrsonnet_types::ValType;14use jrsonnet_types::ValType;
15use rustc_hash::{FxHashMap, FxHasher};15use rustc_hash::{FxHashMap, FxHasher};
254 new_bindings.fill(bindings);254 new_bindings.fill(bindings);
255 }255 }
256256
257 let mut new_members = FxHashMap::default();
258 let mut assertions: Vec<Box<dyn ObjectAssertion>> = Vec::new();257 let mut builder = ObjValueBuilder::new();
259 for member in members.iter() {258 for member in members.iter() {
260 match member {259 match member {
261 Member::Field(FieldMember {260 Member::Field(FieldMember {
291 )?))290 )?))
292 }291 }
293 }292 }
293 builder
294 new_members.insert(294 .member(name.clone())
295 name.clone(),
296 ObjMember {
297 add: *plus,295 .with_add(*plus)
298 visibility: *visibility,296 .with_visibility(*visibility)
297 .with_location(value.1.clone())
299 invoke: LazyBinding::Bindable(Gc::new(Box::new(ObjMemberBinding {298 .bindable(Box::new(ObjMemberBinding {
300 context_creator: context_creator.clone(),299 context_creator: context_creator.clone(),
301 value: value.clone(),300 value: value.clone(),
302 name,301 name,
303 }))),302 }));
304 location: value.1.clone(),
305 },
306 );
307 }303 }
308 Member::Field(FieldMember {304 Member::Field(FieldMember {
309 name,305 name,
338 )))334 )))
339 }335 }
340 }336 }
337 builder
341 new_members.insert(338 .member(name.clone())
342 name.clone(),339 .hide()
343 ObjMember {340 .with_location(value.1.clone())
344 add: false,
345 visibility: Visibility::Hidden,
346 invoke: LazyBinding::Bindable(Gc::new(Box::new(ObjMemberBinding {341 .binding(LazyBinding::Bindable(Gc::new(Box::new(ObjMemberBinding {
347 context_creator: context_creator.clone(),342 context_creator: context_creator.clone(),
348 value: value.clone(),343 value: value.clone(),
349 params: params.clone(),344 params: params.clone(),
350 name,345 name,
351 }))),346 }))));
352 location: value.1.clone(),
353 },
354 );
355 }347 }
356 Member::BindStmt(_) => {}348 Member::BindStmt(_) => {}
357 Member::AssertStmt(stmt) => {349 Member::AssertStmt(stmt) => {
371 evaluate_assert(ctx, &self.assert)363 evaluate_assert(ctx, &self.assert)
372 }364 }
373 }365 }
374 assertions.push(Box::new(ObjectAssert {366 builder.assert(Box::new(ObjectAssert {
375 context_creator: context_creator.clone(),367 context_creator: context_creator.clone(),
376 assert: stmt.clone(),368 assert: stmt.clone(),
377 }));369 }));
378 }370 }
379 }371 }
380 }372 }
381 let this = ObjValue::new(None, Gc::new(new_members), Gc::new(assertions));373 let this = builder.build();
382 future_this.fill(this.clone());374 future_this.fill(this.clone());
383 Ok(this)375 Ok(this)
384}376}
388 ObjBody::MemberList(members) => evaluate_member_list_object(context, members)?,380 ObjBody::MemberList(members) => evaluate_member_list_object(context, members)?,
389 ObjBody::ObjComp(obj) => {381 ObjBody::ObjComp(obj) => {
390 let future_this = FutureWrapper::new();382 let future_this = FutureWrapper::new();
391 let mut new_members = FxHashMap::default();383 let mut builder = ObjValueBuilder::new();
392 evaluate_comp(context.clone(), &obj.compspecs, &mut |ctx| {384 evaluate_comp(context.clone(), &obj.compspecs, &mut |ctx| {
393 let new_bindings = FutureWrapper::new();385 let new_bindings = FutureWrapper::new();
394 let context_creator = ContextCreator(context.clone(), new_bindings.clone());386 let context_creator = ContextCreator(context.clone(), new_bindings.clone());
435 )?))427 )?))
436 }428 }
437 }429 }
430 builder
438 new_members.insert(431 .member(n)
439 n,432 .with_location(obj.value.1.clone())
440 ObjMember {
441 add: false,
442 visibility: Visibility::Normal,
443 invoke: LazyBinding::Bindable(Gc::new(Box::new(ObjCompBinding {433 .bindable(Box::new(ObjCompBinding {
444 context: ctx,434 context: ctx,
445 value: obj.value.clone(),435 value: obj.value.clone(),
446 }))),436 }));
447 location: obj.value.1.clone(),
448 },
449 );
450 }437 }
451 v => throw!(FieldMustBeStringGot(v.value_type())),438 v => throw!(FieldMustBeStringGot(v.value_type())),
452 }439 }
453440
454 Ok(())441 Ok(())
455 })?;442 })?;
456443
457 let this = ObjValue::new(None, Gc::new(new_members), Gc::new(Vec::new()));444 let this = builder.build();
458 future_this.fill(this.clone());445 future_this.fill(this.clone());
459 this446 this
460 }447 }
modifiedcrates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth
--- 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<Val> = 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::<FxHasher>::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())
 			}
 		}
 	}
modifiedcrates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth
--- 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<ObjValue>,
+	map: FxHashMap<IStr, ObjMember>,
+	assertions: Vec<Box<dyn ObjectAssertion>>,
+}
+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::<FxHasher>::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<dyn ObjectAssertion>) -> &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<ExprLocation>,
+}
+
+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<ExprLocation>) -> 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<dyn Bindable>) -> &'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
+	}
+}