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

difftreelog

fix align std.format output with standard jsonnet changes

mykzwksoYaroslav Bolyukin2026-02-08parent: #c368769.patch.diff
in: master

4 files changed

modifiedcrates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate/operator.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/operator.rs
@@ -225,15 +225,20 @@
 			if v2.get() < 0.0 {
 				bail!("shift by negative exponent")
 			}
-			let exp = ((v2.get() as i64) & 63) as u32;
-			Val::try_num((v1.get() as i64).wrapping_shl(exp) as f64)?
+			let base = v1.truncate_for_bitwise()?;
+			let exp = v2.truncate_for_bitwise()? % 64;
+
+			if exp >= 1 && base >= (1i64 << (63 - exp as u32)) {
+				bail!("left shift would overflow")
+			}
+			Val::try_num(base.wrapping_shl(exp as u32) as f64)?
 		}
 		(Num(v1), Rhs, Num(v2)) => {
 			if v2.get() < 0.0 {
 				bail!("shift by negative exponent")
 			}
 			let exp = ((v2.get() as i64) & 63) as u32;
-			Val::try_num((v1.get() as i64).wrapping_shr(exp) as f64)?
+			Val::try_num(v1.truncate_for_bitwise()?.wrapping_shr(exp) as f64)?
 		}
 
 		// Bigint X Bigint
modifiedcrates/jrsonnet-evaluator/src/stdlib/format.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/stdlib/format.rs
+++ b/crates/jrsonnet-evaluator/src/stdlib/format.rs
@@ -137,7 +137,7 @@
 #[derive(Debug, PartialEq, Eq)]
 pub enum Width {
 	Star,
-	Fixed(usize),
+	Fixed(u16),
 }
 pub fn try_parse_field_width(str: &str) -> ParseResult<'_, Width> {
 	if str.is_empty() {
@@ -147,11 +147,11 @@
 	if bytes[0] == b'*' {
 		return Ok((Width::Star, &str[1..]));
 	}
-	let mut out: usize = 0;
+	let mut out: u16 = 0;
 	let mut digits = 0;
 	while let Some(digit) = (bytes[digits] as char).to_digit(10) {
 		out *= 10;
-		out += digit as usize;
+		out += digit as u16;
 		digits += 1;
 		if digits == bytes.len() {
 			return Err(TruncatedFormatCode);
@@ -299,15 +299,18 @@
 #[inline]
 pub fn render_integer(
 	out: &mut String,
+	neg: bool,
 	iv: f64,
-	padding: usize,
-	precision: usize,
+	padding: u16,
+	precision: u16,
 	blank: bool,
 	sign: bool,
 	radix: i64,
-	prefix: &str,
+	zero_prefix: &str,
+	prefix_in_padding: bool,
 	caps: bool,
 ) {
+	debug_assert!(iv >= 0.0, "render_integer receives sign using arg");
 	let iv = iv.floor() as i64;
 	// Digit char indexes in reverse order, i.e
 	// for radix = 16 and n = 12f: [15, 2, 1]
@@ -322,12 +325,14 @@
 		}
 		nums
 	};
-	let neg = iv < 0;
 	#[allow(clippy::bool_to_int_with_if)]
 	let zp = padding.saturating_sub(if neg || blank || sign { 1 } else { 0 });
+
+	let pref_len = zero_prefix.len() as u16;
 	let zp2 = zp
+		.saturating_sub(if !prefix_in_padding { pref_len } else { 0 })
 		.max(precision)
-		.saturating_sub(prefix.len() + digits.len());
+		.saturating_sub(if prefix_in_padding { pref_len } else { 0 } + digits.len() as u16);
 
 	if neg {
 		out.push('-');
@@ -337,11 +342,13 @@
 		out.push(' ');
 	}
 
-	out.reserve(zp2);
+	out.reserve(zp2 as usize);
+	if iv != 0 {
+		out.push_str(zero_prefix);
+	}
 	for _ in 0..zp2 {
 		out.push('0');
 	}
-	out.push_str(prefix);
 
 	for digit in digits.into_iter().rev() {
 		let ch = NUMBERS[digit as usize] as char;
@@ -351,25 +358,30 @@
 
 pub fn render_decimal(
 	out: &mut String,
+	neg: bool,
 	iv: f64,
-	padding: usize,
-	precision: usize,
+	padding: u16,
+	precision: u16,
 	blank: bool,
 	sign: bool,
 ) {
-	render_integer(out, iv, padding, precision, blank, sign, 10, "", false);
+	render_integer(
+		out, neg, iv, padding, precision, blank, sign, 10, "", false, false,
+	);
 }
 pub fn render_octal(
 	out: &mut String,
+	neg: bool,
 	iv: f64,
-	padding: usize,
-	precision: usize,
+	padding: u16,
+	precision: u16,
 	alt: bool,
 	blank: bool,
 	sign: bool,
 ) {
 	render_integer(
 		out,
+		neg,
 		iv,
 		padding,
 		precision,
@@ -377,6 +389,7 @@
 		sign,
 		8,
 		if alt && iv != 0.0 { "0" } else { "" },
+		true,
 		false,
 	);
 }
@@ -385,8 +398,8 @@
 pub fn render_hexadecimal(
 	out: &mut String,
 	iv: f64,
-	padding: usize,
-	precision: usize,
+	padding: u16,
+	precision: u16,
 	alt: bool,
 	blank: bool,
 	sign: bool,
@@ -394,7 +407,8 @@
 ) {
 	render_integer(
 		out,
-		iv,
+		iv < 0.0,
+		iv.abs(),
 		padding,
 		precision,
 		blank,
@@ -405,6 +419,7 @@
 			(true, false) => "0x",
 			(false, _) => "",
 		},
+		false,
 		caps,
 	);
 }
@@ -413,31 +428,36 @@
 pub fn render_float(
 	out: &mut String,
 	n: f64,
-	mut padding: usize,
-	precision: usize,
+	mut padding: u16,
+	precision: u16,
 	blank: bool,
 	sign: bool,
 	ensure_pt: bool,
 	trailing: bool,
 ) {
+	// Represent the rounded number as an integer * 1/10**prec.
+	// Note that it can also be equal to 10**prec and we'll need to carry
+	// over to the wholes.  We operate on the absolute numbers, so that we
+	// don't have trouble with the rounding direction.
+	let denominator = 10.0f64.powi(precision as i32);
+	let numerator = n.abs() * denominator + 0.5;
+	let whole = (numerator / denominator).floor();
+	let frac = numerator.floor() % denominator;
+
 	#[allow(clippy::bool_to_int_with_if)]
 	let dot_size = if precision == 0 && !ensure_pt { 0 } else { 1 };
 	padding = padding.saturating_sub(dot_size + precision);
-	render_decimal(out, n.floor(), padding, 0, blank, sign);
+	render_decimal(out, n < 0.0, whole, padding, 0, blank, sign);
 	if precision == 0 {
 		if ensure_pt {
 			out.push('.');
 		}
 		return;
 	}
-	let frac = n
-		.fract()
-		.mul_add(10.0_f64.powf(precision as f64), 0.5)
-		.floor();
 	if trailing || frac > 0.0 {
 		out.push('.');
 		let mut frac_str = String::new();
-		render_decimal(&mut frac_str, frac, precision, 0, false, false);
+		render_decimal(&mut frac_str, false, frac, precision, 0, false, false);
 		let mut trim = frac_str.len();
 		if !trailing {
 			for b in frac_str.as_bytes().iter().rev() {
@@ -458,25 +478,38 @@
 pub fn render_float_sci(
 	out: &mut String,
 	n: f64,
-	mut padding: usize,
-	precision: usize,
+	mut padding: u16,
+	precision: u16,
 	blank: bool,
 	sign: bool,
 	ensure_pt: bool,
 	trailing: bool,
 	caps: bool,
 ) {
-	let exponent = n.log10().floor();
+	let exponent = if n == 0.0 {
+		0.0
+	} else {
+		n.abs().log10().floor()
+	};
+
 	let mantissa = if exponent as i16 == -324 {
 		n * 10.0 / 10.0_f64.powf(exponent + 1.0)
 	} else {
 		n / 10.0_f64.powf(exponent)
 	};
 	let mut exponent_str = String::new();
-	render_decimal(&mut exponent_str, exponent, 3, 0, false, true);
+	render_decimal(
+		&mut exponent_str,
+		exponent < 0.0,
+		exponent.abs(),
+		3,
+		0,
+		false,
+		true,
+	);
 
 	// +1 for e
-	padding = padding.saturating_sub(exponent_str.len() + 1);
+	padding = padding.saturating_sub(exponent_str.len() as u16 + 1);
 
 	render_float(
 		out, mantissa, padding, precision, blank, sign, ensure_pt, trailing,
@@ -490,8 +523,8 @@
 	out: &mut String,
 	value: &Val,
 	code: &Code<'_>,
-	width: usize,
-	precision: Option<usize>,
+	width: u16,
+	precision: Option<u16>,
 ) -> Result<()> {
 	let clfags = &code.cflags;
 	let (fpprec, iprec) = precision.map_or((6, 0), |v| (v, v));
@@ -510,7 +543,8 @@
 			let value = f64::from_untyped(value.clone())?;
 			render_decimal(
 				&mut tmp_out,
-				value,
+				value <= -1.0,
+				value.abs(),
 				padding,
 				iprec,
 				clfags.blank,
@@ -521,7 +555,8 @@
 			let value = f64::from_untyped(value.clone())?;
 			render_octal(
 				&mut tmp_out,
-				value,
+				value <= -1.0,
+				value.abs(),
 				padding,
 				iprec,
 				clfags.alt,
@@ -589,7 +624,7 @@
 					code.caps,
 				);
 			} else {
-				let digits_before_pt = 1.max(exponent as usize + 1);
+				let digits_before_pt = 1.max(exponent as u16 + 1);
 				render_float(
 					&mut tmp_out,
 					value,
@@ -628,7 +663,7 @@
 		ConvTypeV::Percent => tmp_out.push('%'),
 	};
 
-	let padding = width.saturating_sub(tmp_out.len());
+	let padding = width.saturating_sub(tmp_out.len() as u16);
 
 	if !clfags.left {
 		for _ in 0..padding {
@@ -663,7 +698,7 @@
 						}
 						let value = &values[0];
 						values = &values[1..];
-						usize::from_untyped(value.clone())?
+						u16::from_untyped(value.clone())?
 					}
 					Width::Fixed(n) => n,
 				};
@@ -674,7 +709,7 @@
 						}
 						let value = &values[0];
 						values = &values[1..];
-						Some(usize::from_untyped(value.clone())?)
+						Some(u16::from_untyped(value.clone())?)
 					}
 					Some(Width::Fixed(n)) => Some(n),
 					None => None,
modifiedcrates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/typed/conversions.rs
+++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs
@@ -120,8 +120,8 @@
 	}
 }
 
-pub const MAX_SAFE_INTEGER: f64 = ((1u64 << (f64::MANTISSA_DIGITS + 1)) - 1) as f64;
-pub const MIN_SAFE_INTEGER: f64 = -MAX_SAFE_INTEGER;
+pub const MAX_SAFE_INTEGER: f64 = ((1u64 << (f64::MANTISSA_DIGITS)) - 1) as f64;
+pub const MIN_SAFE_INTEGER: f64 = (-((1i64 << (f64::MANTISSA_DIGITS)) - 1)) as f64;
 
 macro_rules! impl_int {
 	($($ty:ty)*) => {$(
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
22 function::FuncVal,22 function::FuncVal,
23 gc::WithCapacityExt as _,23 gc::WithCapacityExt as _,
24 manifest::{ManifestFormat, ToStringFormat},24 manifest::{ManifestFormat, ToStringFormat},
25 typed::BoundedUsize,25 typed::{BoundedUsize, MAX_SAFE_INTEGER, MIN_SAFE_INTEGER},
26 ObjValue, Result, Unbound, WeakObjValue,26 ObjValue, Result, Unbound, WeakObjValue,
27};27};
2828
418 pub const fn get(&self) -> f64 {418 pub const fn get(&self) -> f64 {
419 self.0419 self.0
420 }420 }
421 pub(crate) fn truncate_for_bitwise(&self) -> Result<i64> {
422 if self.0 < MIN_SAFE_INTEGER || self.0 > dbg!(MAX_SAFE_INTEGER) {
423 bail!("numberic value outside of safe integer range for bitwise operation");
424 }
425 Ok(self.0 as i64)
426 }
421}427}
422impl PartialEq for NumValue {428impl PartialEq for NumValue {
423 fn eq(&self, other: &Self) -> bool {429 fn eq(&self, other: &Self) -> bool {
490 type Error = ConvertNumValueError;496 type Error = ConvertNumValueError;
491 #[inline]497 #[inline]
492 fn try_from(value: $ty) -> Result<Self, ConvertNumValueError> {498 fn try_from(value: $ty) -> Result<Self, ConvertNumValueError> {
493 use crate::typed::conversions::{MIN_SAFE_INTEGER, MAX_SAFE_INTEGER};
494 let value = value as f64;499 let value = value as f64;
495 if value < MIN_SAFE_INTEGER {500 if value < MIN_SAFE_INTEGER {
496 return Err(ConvertNumValueError::Underflow)501 return Err(ConvertNumValueError::Underflow)