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
--- 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<Box<dyn ObjectAssertion>> = 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
 		}
modifiedcrates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth
1use crate::{1use crate::{
2 error::{Error::*, LocError, Result},2 error::{Error::*, LocError, Result},
3 throw, LazyBinding, LazyVal, ObjMember, ObjValue, Val,3 throw, ObjValueBuilder, Val,
4};4};
5use jrsonnet_gc::Gc;
6use jrsonnet_parser::Visibility;
7use rustc_hash::FxHasher;
8use serde_json::{Map, Number, Value};5use serde_json::{Map, Number, Value};
9use std::{6use std::convert::{TryFrom, TryInto};
10 collections::HashMap,
11 convert::{TryFrom, TryInto},
12 hash::BuildHasherDefault,
13};
147
15impl TryFrom<&Val> for Value {8impl TryFrom<&Val> for Value {
16 type Error = LocError;9 type Error = LocError;
54 Value::Number(n) => Self::Num(n.as_f64().expect("as f64")),47 Value::Number(n) => Self::Num(n.as_f64().expect("as f64")),
55 Value::String(s) => Self::Str((s as &str).into()),48 Value::String(s) => Self::Str((s as &str).into()),
56 Value::Array(a) => {49 Value::Array(a) => {
57 let mut out = Vec::with_capacity(a.len());50 let mut out: Vec<Val> = Vec::with_capacity(a.len());
58 for v in a {51 for v in a {
59 out.push(LazyVal::new_resolved(v.into()));52 out.push(v.into());
60 }53 }
61 Self::Arr(out.into())54 Self::Arr(out.into())
62 }55 }
63 Value::Object(o) => {56 Value::Object(o) => {
64 let mut entries = HashMap::with_capacity_and_hasher(57 let mut builder = ObjValueBuilder::with_capacity(o.len());
65 o.len(),
66 BuildHasherDefault::<FxHasher>::default(),
67 );
68 for (k, v) in o {58 for (k, v) in o {
69 entries.insert(59 builder.member((k as &str).into()).value(v.into());
70 (k as &str).into(),
71 ObjMember {
72 add: false,
73 visibility: Visibility::Normal,
74 invoke: LazyBinding::Bound(LazyVal::new_resolved(v.into())),
75 location: None,
76 },
77 );
78 }60 }
79 Self::Obj(ObjValue::new(None, Gc::new(entries), Gc::new(Vec::new())))61 Val::Obj(builder.build())
80 }62 }
81 }63 }
82 }64 }
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
+	}
+}