git.delta.rocks / jrsonnet / refs/commits / 47e40b265d54

difftreelog

Merge pull request #118 from CertainLach/feature/upstream-std-sync

Yaroslav Bolyukin2023-07-17parents: #e0d3ba2 #397e1ed.patch.diff
in: master

11 files changed

modifiedCargo.lockdiffbeforeafterboth
before · Cargo.lock
101 packageslockfile v3
modifiedcrates/jrsonnet-stdlib/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/Cargo.toml
+++ b/crates/jrsonnet-stdlib/Cargo.toml
@@ -32,8 +32,12 @@
 
 # std.md5
 md5 = "0.7.0"
+# std.sha1
+sha1 = "0.10.5"
 # std.sha256, std.sha512
 sha2 = "0.10.6"
+# std.sha3
+sha3 = "0.10.8"
 # std.base64
 base64 = "0.21.0"
 # std.parseJson
modifiedcrates/jrsonnet-stdlib/src/arrays.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/arrays.rs
+++ b/crates/jrsonnet-stdlib/src/arrays.rs
@@ -1,12 +1,22 @@
+#![allow(non_snake_case)]
+
 use jrsonnet_evaluator::{
 	error::{ErrorKind::RuntimeError, Result},
 	function::{builtin, FuncVal},
 	throw,
 	typed::{BoundedI32, BoundedUsize, Either2, NativeFn, Typed},
 	val::{equals, ArrValue, IndexableVal, StrValue},
-	Either, IStr, Val,
+	Either, IStr, Thunk, Val,
 };
 
+pub(crate) fn eval_on_empty(on_empty: Option<Thunk<Val>>) -> Result<Val> {
+	if let Some(on_empty) = on_empty {
+		on_empty.evaluate()
+	} else {
+		throw!("expected non-empty array")
+	}
+}
+
 #[builtin]
 pub fn builtin_make_array(sz: BoundedI32<0, { i32::MAX }>, func: FuncVal) -> Result<ArrValue> {
 	if *sz == 0 {
@@ -221,6 +231,11 @@
 }
 
 #[builtin]
+pub fn builtin_contains(arr: IndexableVal, elem: Val) -> Result<bool> {
+	builtin_member(arr, elem)
+}
+
+#[builtin]
 pub fn builtin_count(arr: ArrValue, x: Val) -> Result<usize> {
 	let mut count = 0;
 	for item in arr.iter() {
@@ -230,3 +245,35 @@
 	}
 	Ok(count)
 }
+
+#[builtin]
+pub fn builtin_avg(arr: Vec<f64>, onEmpty: Option<Thunk<Val>>) -> Result<Val> {
+	if arr.is_empty() {
+		return eval_on_empty(onEmpty);
+	}
+	Ok(Val::Num(arr.iter().sum::<f64>() / (arr.len() as f64)))
+}
+
+#[builtin]
+pub fn builtin_remove_at(
+	arr: ArrValue,
+	index: usize,
+) -> Result<ArrValue> {
+	let newArrLeft = arr.clone().slice(None, Some(index), None);
+	let newArrRight = arr.slice(Some(index + 1), None, None);
+	
+	Ok(ArrValue::extended(
+		newArrLeft.unwrap_or(ArrValue::empty()),
+		newArrRight.unwrap_or(ArrValue::empty()))
+	)
+}
+
+#[builtin]
+pub fn builtin_remove(arr: ArrValue, elem: Val) -> Result<ArrValue> {
+	for (index, item) in arr.iter().enumerate() {
+		if equals(&item?, &elem)? {
+			return builtin_remove_at(arr.clone(), index) 
+		}
+	}
+	Ok(arr)
+}
modifiedcrates/jrsonnet-stdlib/src/hash.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/hash.rs
+++ b/crates/jrsonnet-stdlib/src/hash.rs
@@ -16,3 +16,15 @@
 	use sha2::digest::Digest;
 	format!("{:x}", sha2::Sha512::digest(s.as_bytes()))
 }
+
+#[builtin]
+pub fn builtin_sha1(s: IStr) -> String {
+	use sha1::digest::Digest;
+	format!("{:x}", sha1::Sha1::digest(s.as_bytes()))
+}
+
+#[builtin]
+pub fn builtin_sha3(s: IStr) -> String {
+	use sha3::digest::Digest;
+	format!("{:x}", sha3::Sha3_512::digest(s.as_bytes()))
+}
modifiedcrates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/lib.rs
+++ b/crates/jrsonnet-stdlib/src/lib.rs
@@ -80,7 +80,11 @@
 		("any", builtin_any::INST),
 		("all", builtin_all::INST),
 		("member", builtin_member::INST),
+		("contains", builtin_member::INST),
 		("count", builtin_count::INST),
+		("avg", builtin_avg::INST),
+		("removeAt", builtin_remove_at::INST),
+		("remove", builtin_remove::INST),
 		// Math
 		("abs", builtin_abs::INST),
 		("sign", builtin_sign::INST),
@@ -102,20 +106,30 @@
 		("exp", builtin_exp::INST),
 		("mantissa", builtin_mantissa::INST),
 		("exponent", builtin_exponent::INST),
+		("round", builtin_round::INST),
+		("isEven", builtin_is_even::INST),
+		("isOdd", builtin_is_odd::INST),
+		("isInteger", builtin_is_integer::INST),
+		("isDecimal", builtin_is_decimal::INST),
 		// Operator
 		("mod", builtin_mod::INST),
 		("primitiveEquals", builtin_primitive_equals::INST),
 		("equals", builtin_equals::INST),
 		("xor", builtin_xor::INST),
+		("xnor", builtin_xnor::INST),
 		("format", builtin_format::INST),
 		// Sort
 		("sort", builtin_sort::INST),
 		("uniq", builtin_uniq::INST),
 		("set", builtin_set::INST),
+		("minArray", builtin_min_array::INST),
+		("maxArray", builtin_max_array::INST),
 		// Hash
 		("md5", builtin_md5::INST),
+		("sha1", builtin_sha1::INST),
 		("sha256", builtin_sha256::INST),
 		("sha512", builtin_sha512::INST),
+		("sha3", builtin_sha3::INST),
 		// Encoding
 		("encodeUTF8", builtin_encode_utf8::INST),
 		("decodeUTF8", builtin_decode_utf8::INST),
@@ -125,6 +139,7 @@
 		// Objects
 		("objectFieldsEx", builtin_object_fields_ex::INST),
 		("objectHasEx", builtin_object_has_ex::INST),
+		("objectRemoveKey", builtin_object_remove_key::INST),
 		// Manifest
 		("escapeStringJson", builtin_escape_string_json::INST),
 		("manifestJsonEx", builtin_manifest_json_ex::INST),
@@ -138,6 +153,8 @@
 		("substr", builtin_substr::INST),
 		("char", builtin_char::INST),
 		("strReplace", builtin_str_replace::INST),
+		("isEmpty", builtin_is_empty::INST),
+		("equalsIgnoreCase", builtin_equals_ignore_case::INST),
 		("splitLimit", builtin_splitlimit::INST),
 		("asciiUpper", builtin_ascii_upper::INST),
 		("asciiLower", builtin_ascii_lower::INST),
modifiedcrates/jrsonnet-stdlib/src/math.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/math.rs
+++ b/crates/jrsonnet-stdlib/src/math.rs
@@ -114,3 +114,28 @@
 pub fn builtin_exponent(x: f64) -> i16 {
 	frexp(x).1
 }
+
+#[builtin]
+pub fn builtin_round(x: f64) -> f64 {
+	x.round()
+}
+
+#[builtin]
+pub fn builtin_is_even(x: f64) -> bool {
+	builtin_round(x) % 2.0 == 0.0
+}
+
+#[builtin]
+pub fn builtin_is_odd(x: f64) -> bool {
+	builtin_round(x) % 2.0 == 1.0
+}
+
+#[builtin]
+pub fn builtin_is_integer(x: f64) -> bool {
+	builtin_round(x) == x
+}
+
+#[builtin]
+pub fn builtin_is_decimal(x: f64) -> bool {
+	builtin_round(x) != x
+}
modifiedcrates/jrsonnet-stdlib/src/objects.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/objects.rs
+++ b/crates/jrsonnet-stdlib/src/objects.rs
@@ -1,9 +1,10 @@
 use jrsonnet_evaluator::{
 	function::builtin,
 	val::{StrValue, Val},
-	IStr, ObjValue,
+	IStr, ObjValue, ObjValueBuilder,
 };
 
+
 #[builtin]
 pub fn builtin_object_fields_ex(
 	obj: ObjValue,
@@ -27,3 +28,16 @@
 pub fn builtin_object_has_ex(obj: ObjValue, fname: IStr, hidden: bool) -> bool {
 	obj.has_field_ex(fname, hidden)
 }
+
+#[builtin]
+pub fn builtin_object_remove_key(obj: ObjValue, key: IStr) -> ObjValue {
+	let mut new_obj = ObjValueBuilder::with_capacity(obj.len() - 1);
+	for (k, v) in obj.iter() {
+		if k == key {
+			continue
+		}
+		new_obj.member(k).value_unchecked(v.unwrap())
+	}
+
+	new_obj.build()
+}
modifiedcrates/jrsonnet-stdlib/src/operator.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/operator.rs
+++ b/crates/jrsonnet-stdlib/src/operator.rs
@@ -39,6 +39,11 @@
 }
 
 #[builtin]
+pub fn builtin_xnor(x: bool, y: bool) -> bool {
+	x == y
+}
+
+#[builtin]
 pub fn builtin_format(str: IStr, vals: Val) -> Result<String> {
 	std_format(&str, vals)
 }
modifiedcrates/jrsonnet-stdlib/src/sort.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/sort.rs
+++ b/crates/jrsonnet-stdlib/src/sort.rs
@@ -1,3 +1,5 @@
+#![allow(non_snake_case)]
+
 use std::cmp::Ordering;
 
 use jrsonnet_evaluator::{
@@ -9,6 +11,9 @@
 	Thunk, Val,
 };
 use jrsonnet_gcmodule::Cc;
+use jrsonnet_parser::BinaryOpType;
+
+use crate::eval_on_empty;
 
 #[derive(Copy, Clone)]
 enum SortKeyType {
@@ -64,15 +69,13 @@
 			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, jrsonnet_parser::BinaryOpType::Lt) {
-					Ok(ord) => ord,
-					Err(e) if err.is_none() => {
-						let _ = err.insert(e);
-						Ordering::Equal
-					}
-					Err(_) => Ordering::Equal,
+			values.sort_unstable_by(|a, b| match evaluate_compare_op(a, b, BinaryOpType::Lt) {
+				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);
@@ -105,16 +108,16 @@
 			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, jrsonnet_parser::BinaryOpType::Lt) {
+			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,
-				}
-			});
+				},
+			);
 			if let Some(err) = err {
 				return Err(err);
 			}
@@ -138,7 +141,6 @@
 }
 
 #[builtin]
-#[allow(non_snake_case)]
 pub fn builtin_sort(arr: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {
 	super::sort::sort(arr, keyF.unwrap_or_else(FuncVal::identity))
 }
@@ -206,3 +208,50 @@
 		Ok(ArrValue::lazy(Cc::new(arr)))
 	}
 }
+
+
+fn eval_keyf(val: Val, key_f: &Option<FuncVal>) -> Result<Val> {
+	if let Some(key_f) = key_f {
+		key_f.evaluate_simple(&(val,), false)
+	} else {
+		Ok(val)
+	}
+}
+
+fn array_top1(arr: ArrValue, key_f: Option<FuncVal>, ordering: Ordering) -> Result<Val> {
+	let mut iter = arr.iter();
+	let mut min = iter.next().expect("not empty")?;
+	let mut min_key = eval_keyf(min.clone(), &key_f)?;
+	for item in iter {
+		let cur = item?;
+		let cur_key = eval_keyf(cur.clone(), &key_f)?;
+		if evaluate_compare_op(&cur_key, &min_key, BinaryOpType::Lt)? == ordering {
+			min = cur;
+			min_key = cur_key;
+		}
+	}
+	Ok(min)
+}
+
+#[builtin]
+pub fn builtin_min_array(
+	arr: ArrValue,
+	keyF: Option<FuncVal>,
+	onEmpty: Option<Thunk<Val>>,
+) -> Result<Val> {
+	if arr.is_empty() {
+		return eval_on_empty(onEmpty);
+	}
+	array_top1(arr, keyF, Ordering::Less)
+}
+#[builtin]
+pub fn builtin_max_array(
+	arr: ArrValue,
+	keyF: Option<FuncVal>,
+	onEmpty: Option<Thunk<Val>>,
+) -> Result<Val> {
+	if arr.is_empty() {
+		return eval_on_empty(onEmpty);
+	}
+	array_top1(arr, keyF, Ordering::Greater)
+}
modifiedcrates/jrsonnet-stdlib/src/std.jsonnetdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/std.jsonnet
+++ b/crates/jrsonnet-stdlib/src/std.jsonnet
@@ -274,6 +274,12 @@
   objectValuesAll(o)::
     [o[k] for k in std.objectFieldsAll(o)],
 
+  objectKeysValues(o)::
+    [{ key: k, value: o[k] } for k in std.objectFields(o)],
+	
+  objectKeysValuesAll(o)::
+		[{ key: k, value: o[k] } for k in std.objectFieldsAll(o)],
+
   resolvePath(f, r)::
     local arr = std.split(f, '/');
     std.join('/', std.makeArray(std.length(arr) - 1, function(i) arr[i]) + [r]),
modifiedcrates/jrsonnet-stdlib/src/strings.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/strings.rs
+++ b/crates/jrsonnet-stdlib/src/strings.rs
@@ -28,6 +28,16 @@
 }
 
 #[builtin]
+pub fn builtin_is_empty(str: String) -> bool {
+	str.is_empty()
+}
+
+#[builtin]
+pub fn builtin_equals_ignore_case(x: String, y: String) -> bool {
+	x.to_ascii_lowercase() == y.to_ascii_lowercase()
+}
+
+#[builtin]
 pub fn builtin_splitlimit(str: IStr, c: IStr, maxsplits: Either![usize, M1]) -> ArrValue {
 	use Either2::*;
 	match maxsplits {