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

difftreelog

refactor do not expose direct operator evaluator access

rkvzpxtpYaroslav Bolyukin2026-04-25parent: #c420c56.patch.diff
in: master

7 files changed

modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -10,18 +10,14 @@
 
 use jrsonnet_gcmodule::{Acyclic, Cc, Trace, cc_dyn};
 use jrsonnet_interner::IStr;
+use jrsonnet_ir::BinaryOpType;
 pub use jrsonnet_macros::Thunk;
 use jrsonnet_types::ValType;
 use rustc_hash::FxHashMap;
 
 pub use crate::arr::{ArrValue, ArrayLike};
 use crate::{
-	NumValue, ObjValue, Result, SupThis, Unbound, WeakSupThis, bail,
-	error::{Error, ErrorKind::*},
-	function::FuncVal,
-	gc::WithCapacityExt as _,
-	manifest::{ManifestFormat, ToStringFormat},
-	typed::BoundedUsize,
+	NumValue, ObjValue, Result, SupThis, Unbound, WeakSupThis, bail, error::{Error, ErrorKind::*}, evaluate::operator::{evaluate_compare_op, evaluate_mod_op}, function::FuncVal, gc::WithCapacityExt as _, manifest::{ManifestFormat, ToStringFormat}, typed::BoundedUsize
 };
 
 pub trait ThunkValue: Trace {
@@ -585,6 +581,13 @@
 	pub fn arr(a: impl ArrayLike) -> Self {
 		Self::Arr(ArrValue::new(a))
 	}
+
+	pub fn try_cmp(a: &Val, b: &Val) -> Result<Ordering> {
+		evaluate_compare_op(a, b, BinaryOpType::Lt)
+	}
+	pub fn try_mod(a: &Val, b: &Val) -> Result<Val> {
+		evaluate_mod_op(a, b)
+	}
 }
 
 impl From<IStr> for Val {
modifiedcrates/jrsonnet-stdlib/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/Cargo.toml
+++ b/crates/jrsonnet-stdlib/Cargo.toml
@@ -16,17 +16,13 @@
 # Bigint type
 exp-bigint = ["dep:num-bigint", "jrsonnet-evaluator/exp-bigint"]
 
-exp-null-coaelse = [
-  "jrsonnet-ir/exp-null-coaelse",
-  "jrsonnet-evaluator/exp-null-coaelse",
-]
+exp-null-coaelse = ["jrsonnet-evaluator/exp-null-coaelse"]
 # std.regexMatch and other helpers
 exp-regex = ["dep:regex", "dep:lru", "dep:rustc-hash"]
 
 [dependencies]
 jrsonnet-evaluator.workspace = true
 jrsonnet-macros.workspace = true
-jrsonnet-ir.workspace = true
 jrsonnet-gcmodule.workspace = true
 
 # Used for std.parseJson/std.parseYaml
modifiedcrates/jrsonnet-stdlib/src/compat.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/compat.rs
+++ b/crates/jrsonnet-stdlib/src/compat.rs
@@ -1,19 +1,15 @@
 use std::cmp::Ordering;
 
-use jrsonnet_evaluator::{
-	Result, Val, function::builtin, operator::evaluate_compare_op, val::ArrValue,
-};
+use jrsonnet_evaluator::{function::builtin, val::ArrValue, Result, Val};
 
 #[builtin]
 #[allow(non_snake_case)]
 pub fn builtin___compare(v1: Val, v2: Val) -> Result<i32> {
-	Ok(
-		match evaluate_compare_op(&v1, &v2, jrsonnet_ir::BinaryOpType::Lt)? {
-			Ordering::Less => -1,
-			Ordering::Equal => 0,
-			Ordering::Greater => 1,
-		},
-	)
+	Ok(match Val::try_cmp(&v1, &v2)? {
+		Ordering::Less => -1,
+		Ordering::Equal => 0,
+		Ordering::Greater => 1,
+	})
 }
 
 #[builtin]
@@ -27,11 +23,7 @@
 		#[builtin]
 		#[allow(non_snake_case)]
 		pub fn $name(arr1: ArrValue, arr2: ArrValue) -> Result<bool> {
-			let ordering = evaluate_compare_op(
-				&Val::Arr(arr1),
-				&Val::Arr(arr2),
-				jrsonnet_ir::BinaryOpType::Lt,
-			)?;
+			let ordering = Val::try_cmp(&Val::Arr(arr1), &Val::Arr(arr2))?;
 			Ok($operator.contains(&ordering))
 		}
 	};
modifiedcrates/jrsonnet-stdlib/src/operator.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/operator.rs
+++ b/crates/jrsonnet-stdlib/src/operator.rs
@@ -2,18 +2,17 @@
 //! However, in our case we instead implement them in native, and implement native functions on top of core for backwards compatibility
 
 use jrsonnet_evaluator::{
-	IStr, NumValue, Result, Val,
 	function::builtin,
-	operator::evaluate_mod_op,
 	stdlib::std_format,
 	typed::{Either, Either2},
 	val::{equals, primitive_equals},
+	IStr, NumValue, Result, Val,
 };
 
 #[builtin]
 pub fn builtin_mod(a: Either![NumValue, IStr], b: Val) -> Result<Val> {
 	use Either2::*;
-	evaluate_mod_op(
+	Val::try_mod(
 		&match a {
 			A(v) => Val::Num(v),
 			B(s) => Val::string(s),
modifiedcrates/jrsonnet-stdlib/src/sets.rsdiffbeforeafterboth
before · crates/jrsonnet-stdlib/src/sets.rs
1use std::cmp::Ordering;23use jrsonnet_evaluator::{4	Result, Thunk, Val, function::builtin, operator::evaluate_compare_op, val::ArrValue,5};6use jrsonnet_ir::BinaryOpType;78use crate::keyf::KeyF;910#[builtin]11#[allow(non_snake_case)]12pub fn builtin_set_member(x: Thunk<Val>, arr: ArrValue, #[default] keyF: KeyF) -> Result<bool> {13	let mut low = 0;14	let mut high = arr.len();1516	let x = keyF.eval(x)?;1718	while low < high {19		let middle = usize::midpoint(high, low);20		let comp = keyF.eval(arr.get_lazy(middle).expect("in bounds"))?;21		match evaluate_compare_op(&comp, &x, BinaryOpType::Lt)? {22			Ordering::Less => low = middle + 1,23			Ordering::Equal => return Ok(true),24			Ordering::Greater => high = middle,25		}26	}27	Ok(false)28}2930#[builtin]31#[allow(non_snake_case, clippy::redundant_closure)]32pub fn builtin_set_inter(33	a: ArrValue,34	b: ArrValue,35	#[default] keyF: KeyF,36) -> Result<Vec<Thunk<Val>>> {37	let mut a = a.iter_lazy();38	let mut b = b.iter_lazy();3940	let keyF = |v| keyF.eval(v);4142	let mut av = a.next();43	let mut bv = b.next();44	let mut ak = av.clone().map(keyF).transpose()?;45	let mut bk = bv.map(keyF).transpose()?;4647	let mut out = Vec::new();48	while let (Some(ac), Some(bc)) = (&ak, &bk) {49		match evaluate_compare_op(ac, bc, BinaryOpType::Lt)? {50			Ordering::Less => {51				av = a.next();52				ak = av.clone().map(keyF).transpose()?;53			}54			Ordering::Greater => {55				bv = b.next();56				bk = bv.map(keyF).transpose()?;57			}58			Ordering::Equal => {59				out.push(av.clone().expect("ak != None => av != None"));60				av = a.next();61				ak = av.clone().map(keyF).transpose()?;62				bv = b.next();63				bk = bv.map(keyF).transpose()?;64			}65		}66	}67	Ok(out)68}6970#[builtin]71#[allow(non_snake_case, clippy::redundant_closure)]72pub fn builtin_set_diff(73	a: ArrValue,74	b: ArrValue,75	#[default] keyF: KeyF,76) -> Result<Vec<Thunk<Val>>> {77	let mut a = a.iter_lazy();78	let mut b = b.iter_lazy();7980	let keyF = |v| keyF.eval(v);8182	let mut av = a.next();83	let mut bv = b.next();84	let mut ak = av.clone().map(keyF).transpose()?;85	let mut bk = bv.map(keyF).transpose()?;8687	let mut out = Vec::new();88	while let (Some(ac), Some(bc)) = (&ak, &bk) {89		match evaluate_compare_op(ac, bc, BinaryOpType::Lt)? {90			Ordering::Less => {91				// In a, but not in b92				out.push(av.clone().expect("ak != None"));93				av = a.next();94				ak = av.clone().map(keyF).transpose()?;95			}96			Ordering::Greater => {97				bv = b.next();98				bk = bv.map(keyF).transpose()?;99			}100			Ordering::Equal => {101				av = a.next();102				ak = av.clone().map(keyF).transpose()?;103				bv = b.next();104				bk = bv.map(keyF).transpose()?;105			}106		}107	}108	while let Some(_ac) = &ak {109		// In a, but not in b110		out.push(av.clone().expect("ak != None"));111		av = a.next();112		ak = av.clone().map(keyF).transpose()?;113	}114	Ok(out)115}116117#[builtin]118#[allow(non_snake_case, clippy::redundant_closure)]119pub fn builtin_set_union(120	a: ArrValue,121	b: ArrValue,122	#[default] keyF: KeyF,123) -> Result<Vec<Thunk<Val>>> {124	let mut a = a.iter_lazy();125	let mut b = b.iter_lazy();126127	let keyF = |v| keyF.eval(v);128129	let mut av = a.next();130	let mut bv = b.next();131	let mut ak = av.clone().map(keyF).transpose()?;132	let mut bk = bv.clone().map(keyF).transpose()?;133134	let mut out = Vec::new();135	while let (Some(ac), Some(bc)) = (&ak, &bk) {136		match evaluate_compare_op(ac, bc, BinaryOpType::Lt)? {137			Ordering::Less => {138				out.push(av.clone().expect("ak != None"));139				av = a.next();140				ak = av.clone().map(keyF).transpose()?;141			}142			Ordering::Greater => {143				out.push(bv.clone().expect("bk != None"));144				bv = b.next();145				bk = bv.clone().map(keyF).transpose()?;146			}147			Ordering::Equal => {148				// NOTE: order matters, values in `a` win149				out.push(av.clone().expect("ak != None"));150				av = a.next();151				ak = av.clone().map(keyF).transpose()?;152				bv = b.next();153				bk = bv.clone().map(keyF).transpose()?;154			}155		}156	}157	// a.len() > b.len()158	while let Some(_ac) = &ak {159		out.push(av.clone().expect("ak != None"));160		av = a.next();161		ak = av.clone().map(keyF).transpose()?;162	}163	// b.len() > a.len()164	while let Some(_bc) = &bk {165		out.push(bv.clone().expect("ak != None"));166		bv = b.next();167		bk = bv.clone().map(keyF).transpose()?;168	}169	Ok(out)170}
after · crates/jrsonnet-stdlib/src/sets.rs
1use std::cmp::Ordering;23use jrsonnet_evaluator::{function::builtin, val::ArrValue, Result, Thunk, Val};45use crate::keyf::KeyF;67#[builtin]8#[allow(non_snake_case)]9pub fn builtin_set_member(x: Thunk<Val>, arr: ArrValue, #[default] keyF: KeyF) -> Result<bool> {10	let mut low = 0;11	let mut high = arr.len();1213	let x = keyF.eval(x)?;1415	while low < high {16		let middle = u32::midpoint(high, low);17		let comp = keyF.eval(arr.get_lazy(middle).expect("in bounds"))?;18		match Val::try_cmp(&comp, &x)? {19			Ordering::Less => low = middle + 1,20			Ordering::Equal => return Ok(true),21			Ordering::Greater => high = middle,22		}23	}24	Ok(false)25}2627#[builtin]28#[allow(non_snake_case, clippy::redundant_closure)]29pub fn builtin_set_inter(30	a: ArrValue,31	b: ArrValue,32	#[default] keyF: KeyF,33) -> Result<Vec<Thunk<Val>>> {34	let mut a = a.iter_lazy();35	let mut b = b.iter_lazy();3637	let keyF = |v| keyF.eval(v);3839	let mut av = a.next();40	let mut bv = b.next();41	let mut ak = av.clone().map(keyF).transpose()?;42	let mut bk = bv.map(keyF).transpose()?;4344	let mut out = Vec::new();45	while let (Some(ac), Some(bc)) = (&ak, &bk) {46		match Val::try_cmp(ac, bc)? {47			Ordering::Less => {48				av = a.next();49				ak = av.clone().map(keyF).transpose()?;50			}51			Ordering::Greater => {52				bv = b.next();53				bk = bv.map(keyF).transpose()?;54			}55			Ordering::Equal => {56				out.push(av.clone().expect("ak != None => av != None"));57				av = a.next();58				ak = av.clone().map(keyF).transpose()?;59				bv = b.next();60				bk = bv.map(keyF).transpose()?;61			}62		}63	}64	Ok(out)65}6667#[builtin]68#[allow(non_snake_case, clippy::redundant_closure)]69pub fn builtin_set_diff(70	a: ArrValue,71	b: ArrValue,72	#[default] keyF: KeyF,73) -> Result<Vec<Thunk<Val>>> {74	let mut a = a.iter_lazy();75	let mut b = b.iter_lazy();7677	let keyF = |v| keyF.eval(v);7879	let mut av = a.next();80	let mut bv = b.next();81	let mut ak = av.clone().map(keyF).transpose()?;82	let mut bk = bv.map(keyF).transpose()?;8384	let mut out = Vec::new();85	while let (Some(ac), Some(bc)) = (&ak, &bk) {86		match Val::try_cmp(ac, bc)? {87			Ordering::Less => {88				// In a, but not in b89				out.push(av.clone().expect("ak != None"));90				av = a.next();91				ak = av.clone().map(keyF).transpose()?;92			}93			Ordering::Greater => {94				bv = b.next();95				bk = bv.map(keyF).transpose()?;96			}97			Ordering::Equal => {98				av = a.next();99				ak = av.clone().map(keyF).transpose()?;100				bv = b.next();101				bk = bv.map(keyF).transpose()?;102			}103		}104	}105	while let Some(_ac) = &ak {106		// In a, but not in b107		out.push(av.clone().expect("ak != None"));108		av = a.next();109		ak = av.clone().map(keyF).transpose()?;110	}111	Ok(out)112}113114#[builtin]115#[allow(non_snake_case, clippy::redundant_closure)]116pub fn builtin_set_union(117	a: ArrValue,118	b: ArrValue,119	#[default] keyF: KeyF,120) -> Result<Vec<Thunk<Val>>> {121	let mut a = a.iter_lazy();122	let mut b = b.iter_lazy();123124	let keyF = |v| keyF.eval(v);125126	let mut av = a.next();127	let mut bv = b.next();128	let mut ak = av.clone().map(keyF).transpose()?;129	let mut bk = bv.clone().map(keyF).transpose()?;130131	let mut out = Vec::new();132	while let (Some(ac), Some(bc)) = (&ak, &bk) {133		match Val::try_cmp(ac, bc)? {134			Ordering::Less => {135				out.push(av.clone().expect("ak != None"));136				av = a.next();137				ak = av.clone().map(keyF).transpose()?;138			}139			Ordering::Greater => {140				out.push(bv.clone().expect("bk != None"));141				bv = b.next();142				bk = bv.clone().map(keyF).transpose()?;143			}144			Ordering::Equal => {145				// NOTE: order matters, values in `a` win146				out.push(av.clone().expect("ak != None"));147				av = a.next();148				ak = av.clone().map(keyF).transpose()?;149				bv = b.next();150				bk = bv.clone().map(keyF).transpose()?;151			}152		}153	}154	// a.len() > b.len()155	while let Some(_ac) = &ak {156		out.push(av.clone().expect("ak != None"));157		av = a.next();158		ak = av.clone().map(keyF).transpose()?;159	}160	// b.len() > a.len()161	while let Some(_bc) = &bk {162		out.push(bv.clone().expect("ak != None"));163		bv = b.next();164		bk = bv.clone().map(keyF).transpose()?;165	}166	Ok(out)167}
modifiedcrates/jrsonnet-stdlib/src/sort.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/sort.rs
+++ b/crates/jrsonnet-stdlib/src/sort.rs
@@ -3,12 +3,11 @@
 use std::cmp::Ordering;
 
 use jrsonnet_evaluator::{
-	Result, Thunk, Val, bail,
+	bail,
 	function::builtin,
-	operator::evaluate_compare_op,
-	val::{ArrValue, equals},
+	val::{equals, ArrValue},
+	Result, Thunk, Val,
 };
-use jrsonnet_ir::BinaryOpType;
 
 use crate::{eval_on_empty, keyf::KeyF};
 
@@ -53,7 +52,7 @@
 			let mut err = None;
 			// evaluate_compare_op will never return equal on types, which are different from
 			// jsonnet perspective
-			values.sort_unstable_by(|a, b| match evaluate_compare_op(a, b, BinaryOpType::Lt) {
+			values.sort_unstable_by(|a, b| match Val::try_cmp(a, b) {
 				Ok(ord) => ord,
 				Err(e) if err.is_none() => {
 					let _ = err.insert(e);
@@ -71,7 +70,7 @@
 
 fn sort_keyf(values: ArrValue, keyf: KeyF) -> Result<Vec<Thunk<Val>>> {
 	// Slow path, user provided key getter
-	let mut vk = Vec::with_capacity(values.len());
+	let mut vk = Vec::with_capacity(values.len() as usize);
 	for value in values.iter_lazy() {
 		vk.push((value.clone(), keyf.eval(value)?));
 	}
@@ -89,16 +88,14 @@
 			let mut err = None;
 			// evaluate_compare_op will never return equal on types, which are different from
 			// jsonnet perspective
-			vk.sort_by(
-				|(_a, ak), (_b, bk)| match evaluate_compare_op(ak, bk, BinaryOpType::Lt) {
-					Ok(ord) => ord,
-					Err(e) if err.is_none() => {
-						let _ = err.insert(e);
-						Ordering::Equal
-					}
-					Err(_) => Ordering::Equal,
-				},
-			);
+			vk.sort_by(|(_a, ak), (_b, bk)| match Val::try_cmp(ak, bk) {
+				Ok(ord) => ord,
+				Err(e) if err.is_none() => {
+					let _ = err.insert(e);
+					Ordering::Equal
+				}
+				Err(_) => Ordering::Equal,
+			});
 			if let Some(err) = err {
 				return Err(err);
 			}
@@ -195,7 +192,7 @@
 	for item in iter {
 		let cur = item?;
 		let cur_key = keyf.eval(Thunk::evaluated(cur.clone()))?;
-		if evaluate_compare_op(&cur_key, &min_key, BinaryOpType::Lt)? == ordering {
+		if Val::try_cmp(&cur_key, &min_key)? == ordering {
 			min = cur;
 			min_key = cur_key;
 		}
modifiedcrates/jrsonnet-stdlib/src/strings.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/strings.rs
+++ b/crates/jrsonnet-stdlib/src/strings.rs
@@ -26,7 +26,7 @@
 #[builtin]
 pub fn builtin_str_replace(str: String, from: IStr, to: IStr) -> Result<String> {
 	if from.is_empty() {
-		bail!("'from' string must not be zero length");
+		bail!("`from` string must not be zero length");
 	}
 	Ok(str.replace(&from as &str, &to as &str))
 }