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

difftreelog

perf(evaluator) faster std.equals

Лач2020-07-02parent: #5c0b9a1.patch.diff
in: master

4 files changed

modifiedcrates/jrsonnet-evaluator/build.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/build.rs
+++ b/crates/jrsonnet-evaluator/build.rs
@@ -35,7 +35,7 @@
 								Member::Field(FieldMember {
 									name: FieldName::Fixed(name),
 									..
-								}) if **name == *"join" || **name == *"manifestJsonEx" || **name == *"escapeStringJson"
+								}) if **name == *"join" || **name == *"manifestJsonEx" || **name == *"escapeStringJson" || **name == *"equals"
 							)
 						})
 						.collect(),
modifiedcrates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate.rs
@@ -484,7 +484,14 @@
 				0, a, vec![];
 				1, b, vec![];
 			], {
-				Val::Bool(a == b)
+				Val::Bool(primitive_equals(&a, &b)?)
+			}),
+			// faster
+			("std", "equals") => parse_args!(context, "std.equals", args, 2, [
+				0, a, vec![];
+				1, b, vec![];
+			], {
+				Val::Bool(equals(&a, &b)?)
 			}),
 			("std", "modulo") => parse_args!(context, "std.modulo", args, 2, [
 				0, a: [Val::Num]!!Val::Num, vec![ValType::Num];
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -380,7 +380,7 @@
 #[cfg(test)]
 pub mod tests {
 	use super::Val;
-	use crate::EvaluationState;
+	use crate::{create_error, EvaluationState, primitive_equals};
 	use jrsonnet_parser::*;
 	use std::{path::PathBuf, rc::Rc};
 
@@ -411,11 +411,11 @@
 	fn eval_state_standard() {
 		let state = EvaluationState::default();
 		state.with_stdlib();
-		assert_eq!(
-			state
-				.parse_evaluate_raw(r#"std.assertEqual(std.base64("test"), "dGVzdA==")"#)
-				.unwrap(),
-			Val::Bool(true)
+		assert!(
+			primitive_equals(
+				&state.parse_evaluate_raw(r#"std.assertEqual(std.base64("test"), "dGVzdA==")"#).unwrap(),
+				&Val::Bool(true),
+			).unwrap()
 		);
 	}
 
@@ -445,14 +445,14 @@
 	/// Asserts given code returns `true`
 	macro_rules! assert_eval {
 		($str: expr) => {
-			assert_eq!(eval!($str), Val::Bool(true))
+			assert!(primitive_equals(&eval!($str), &Val::Bool(true)).unwrap())
 		};
 	}
 
 	/// Asserts given code returns `false`
 	macro_rules! assert_eval_neg {
 		($str: expr) => {
-			assert_eq!(eval!($str), Val::Bool(false))
+			assert!(primitive_equals(&eval!($str), &Val::Bool(false)).unwrap())
 		};
 	}
 	macro_rules! assert_json {
@@ -663,9 +663,11 @@
 
 	#[test]
 	fn string_is_string() {
-		assert_eq!(
-			eval!("local arr = 'hello'; (!std.isArray(arr)) && (!std.isString(arr))"),
-			Val::Bool(false)
+		assert!(
+			primitive_equals(
+				&eval!("local arr = 'hello'; (!std.isArray(arr)) && (!std.isString(arr))"),
+				&Val::Bool(false),
+			).unwrap()
 		);
 	}
 
@@ -767,4 +769,10 @@
 			)
 		})
 	}
+
+	#[test]
+	fn equality(){
+		println!("{:?}", jrsonnet_parser::parse("{ x: 1, y: 2 } == { x: 1, y: 2 }", &ParserSettings::default()));
+		assert_eval!("{ x: 1, y: 2 } == { x: 1, y: 2 }")
+	}
 }
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
111 }111 }
112}112}
113113
114#[derive(Debug, PartialEq, Clone)]114#[derive(Debug, Clone)]
115pub enum Val {115pub enum Val {
116 Bool(bool),116 Bool(bool),
117 Null,117 Null,
212 }212 }
213}213}
214
215fn is_function_like(val: &Val) -> bool {
216 matches!(val, Val::Func(_) | Val::Intristic(_, _))
217}
218
219/// Implements std.primitiveEquals builtin
220pub fn primitive_equals(val_a: &Val, val_b: &Val) -> Result<bool> {
221 Ok(match (val_a.unwrap_if_lazy()?, val_b.unwrap_if_lazy()?) {
222 (Val::Bool(a), Val::Bool(b)) => a == b,
223 (Val::Null, Val::Null) => true,
224 (Val::Str(a), Val::Str(b)) => a == b,
225 (Val::Num(a), Val::Num(b)) => (a - b).abs() <= f64::EPSILON,
226 (Val::Arr(_), Val::Arr(_)) => create_error_result(Error::RuntimeError(
227 "primitiveEquals operates on primitive types, got array".into(),
228 ))?,
229 (Val::Obj(_), Val::Obj(_)) => create_error_result(Error::RuntimeError(
230 "primitiveEquals operates on primitive types, got object".into(),
231 ))?,
232 (a, b) if is_function_like(&a) && is_function_like(&b) => create_error_result(
233 Error::RuntimeError("cannot test equality of functions".into()),
234 )?,
235 (_, _) => false,
236 })
237}
238
239/// Native implementation of std.equals
240pub fn equals(val_a: &Val, val_b: &Val) -> Result<bool> {
241 let val_a = val_a.unwrap_if_lazy()?;
242 let val_b = val_b.unwrap_if_lazy()?;
243
244 if val_a.value_type()? != val_b.value_type()? {
245 return Ok(false);
246 }
247 match (val_a, val_b) {
248 // Cant test for ptr equality, because all fields needs to be evaluated
249 (Val::Arr(a), Val::Arr(b)) => {
250 if a.len() != b.len() {
251 return Ok(false);
252 }
253 for (a, b) in a.iter().zip(b.iter()) {
254 if !equals(&a.unwrap_if_lazy()?, &b.unwrap_if_lazy()?)? {
255 return Ok(false);
256 }
257 }
258 Ok(true)
259 }
260 (Val::Obj(a), Val::Obj(b)) => {
261 let fields = a.visible_fields();
262 if fields != b.visible_fields() {
263 return Ok(false);
264 }
265 for field in fields {
266 if !equals(&a.get(field.clone())?.unwrap(), &b.get(field)?.unwrap())? {
267 return Ok(false);
268 }
269 }
270 Ok(true)
271 }
272 (a, b) => Ok(primitive_equals(&a, &b)?),
273 }
274}
214275
215pub fn manifest_json_ex(val: &Val, padding: &str) -> Result<String> {276pub fn manifest_json_ex(val: &Val, padding: &str) -> Result<String> {
216 let mut out = String::new();277 let mut out = String::new();