difftreelog
fix align std.format output with standard jsonnet changes
in: master
4 files changed
crates/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
crates/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,
crates/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)*) => {$(
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth22 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};2828418 pub const fn get(&self) -> f64 {418 pub const fn get(&self) -> f64 {419 self.0419 self.0420 }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)