difftreelog
refactor NumValue::{MIN,MAX}_SAFE_INTEGER constants
in: master
2 files changed
crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth3use jrsonnet_gcmodule::Trace;3use jrsonnet_gcmodule::Trace;4use jrsonnet_interner::{IBytes, IStr};4use jrsonnet_interner::{IBytes, IStr};5use jrsonnet_ir::NumValue;5use jrsonnet_ir::NumValue;6pub use jrsonnet_ir::{MAX_SAFE_INTEGER, MIN_SAFE_INTEGER};7use jrsonnet_types::{ComplexValType, ValType};6use jrsonnet_types::{ComplexValType, ValType};879use crate::{8use crate::{377}376}378impl Typed for usize {377impl Typed for usize {379 const TYPE: &'static ComplexValType =378 const TYPE: &'static ComplexValType =380 &ComplexValType::BoundedNumber(Some(0.0), Some(MAX_SAFE_INTEGER));379 &ComplexValType::BoundedNumber(Some(0.0), Some(NumValue::MAX_SAFE_INTEGER));381}380}382impl IntoUntyped for usize {381impl IntoUntyped for usize {383 fn into_untyped(value: Self) -> Result<Val> {382 fn into_untyped(value: Self) -> Result<Val> {crates/jrsonnet-ir/src/lib.rsdiffbeforeafterboth1#![allow(clippy::redundant_closure_call, clippy::derive_partial_eq_without_eq)]1#![allow(clippy::redundant_closure_call, clippy::derive_partial_eq_without_eq)]2//! Jrsonnet AST definitions233mod expr;4mod expr;4use std::{cmp::Ordering, fmt, ops::Deref};5use std::{cmp::Ordering, fmt, ops::Deref};17 SourcePathT, SourceUrl, SourceVirtual,18 SourcePathT, SourceUrl, SourceVirtual,18};19};1920// It seels to be a wrong place for this kind of stuff, but as it would also be used for static analysis and21// is already wanted for NumValue, I don't know a better place.22#[expect(clippy::cast_precision_loss, reason = "checked to not overflow")]23pub const MAX_SAFE_INTEGER: f64 = ((1u64 << (f64::MANTISSA_DIGITS)) - 1) as f64;24#[expect(clippy::cast_precision_loss, reason = "checked to not overflow")]25pub const MIN_SAFE_INTEGER: f64 = (-((1i64 << (f64::MANTISSA_DIGITS)) - 1)) as f64;262027/// Represents jsonnet number21/// Represents jsonnet number28/// Jsonnet numbers are finite f64, with NaNs disallowed22/// Jsonnet numbers are finite f64, with NaNs disallowed29#[derive(Acyclic, Clone, Copy)]23#[derive(Acyclic, Clone, Copy)]30pub struct NumValue(f64);24pub struct NumValue(f64);31impl NumValue {25impl NumValue {26 /// Maximum safe integer value (`2**53 - 1`), see [`NumValue::truncate_for_bitwise`]27 #[expect(clippy::cast_precision_loss, reason = "checked to not overflow")]28 pub const MAX_SAFE_INTEGER: f64 = ((1u64 << (f64::MANTISSA_DIGITS)) - 1) as f64;29 /// Minimum safe integer value (`-(2**53 - 1)`), see [`NumValue::truncate_for_bitwise`]30 #[expect(clippy::cast_precision_loss, reason = "checked to not overflow")]31 pub const MIN_SAFE_INTEGER: f64 = (-((1i64 << (f64::MANTISSA_DIGITS)) - 1)) as f64;3232 /// Creates a [`NumValue`], if value is finite and not NaN33 /// Creates a [`NumValue`], if value is finite and not NaN33 pub fn new(v: f64) -> Option<Self> {34 pub fn new(v: f64) -> Option<Self> {36 }37 }37 Some(Self(v))38 Some(Self(v))38 }39 }40 /// Get the number value39 #[inline]41 #[inline]40 pub const fn get(&self) -> f64 {42 pub const fn get(&self) -> f64 {41 self.043 self.042 }44 }4546 /// In Jsonnet bitwise operations operate on integers,47 /// this method performs a safe conversion for such operation, where we use the same definition for safe as JS:48 ///49 /// Double precision floating point format only has 52 bits to represent the mantissa,50 /// so it can only safely represent integers between -(253 – 1) and 253 – 1.51 /// "Safe" in this context refers to the ability to represent integers exactly and52 /// to compare them correctly. For example, Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 253 /// will evaluate to true, which is mathematically incorrect. See Number.isSafeInteger() for more information.43 pub fn truncate_for_bitwise(self) -> Result<i64, ConvertNumValueError> {54 pub fn truncate_for_bitwise(self) -> Result<i64, ConvertNumValueError> {44 if self.0 < MIN_SAFE_INTEGER || self.0 > MAX_SAFE_INTEGER {55 if self.0 < Self::MIN_SAFE_INTEGER || self.0 > Self::MAX_SAFE_INTEGER {45 return Err(ConvertNumValueError::BitwiseSafeRange);56 return Err(ConvertNumValueError::BitwiseSafeRange);46 }57 }47 #[expect(clippy::cast_possible_truncation, reason = "intended")]58 #[expect(clippy::cast_possible_truncation, reason = "intended")]98}109}99impl_num!(i8, u8, i16, u16, i32, u32);110impl_num!(i8, u8, i16, u16, i32, u32);100111112/// Jsonnet numbers are finite f64, with NaNs disallowed,113/// this enum represents errors that might occur in conversion from/to the [`NumValue`]101#[derive(Clone, Copy, Debug, thiserror::Error, Acyclic)]114#[derive(Clone, Copy, Debug, thiserror::Error, Acyclic)]102pub enum ConvertNumValueError {115pub enum ConvertNumValueError {116 /// The value is too large103 #[error("overflow")]117 #[error("overflow")]104 Overflow,118 Overflow,119 /// The value is too small105 #[error("underflow")]120 #[error("underflow")]106 Underflow,121 Underflow,122 /// Jsonnet numbers can only be finite107 #[error("non-finite")]123 #[error("non-finite")]108 NonFinite,124 NonFinite,125 /// Number value is out of safe integer range109 #[error("float out of safe int range")]126 #[error("float out of safe int range")]110 BitwiseSafeRange,127 BitwiseSafeRange,111}128}118 fn try_from(value: $ty) -> Result<Self, ConvertNumValueError> {135 fn try_from(value: $ty) -> Result<Self, ConvertNumValueError> {119 #[expect(clippy::cast_precision_loss, reason = "precision loss is explicitly handled")]136 #[expect(clippy::cast_precision_loss, reason = "precision loss is explicitly handled")]120 let value = value as f64;137 let value = value as f64;121 if value < MIN_SAFE_INTEGER {138 if value < NumValue::MIN_SAFE_INTEGER {122 return Err(ConvertNumValueError::Underflow)139 return Err(ConvertNumValueError::Underflow)123 } else if value > MAX_SAFE_INTEGER {140 } else if value > NumValue::MAX_SAFE_INTEGER {124 return Err(ConvertNumValueError::Overflow)141 return Err(ConvertNumValueError::Overflow)125 }142 }126 // Number is finite.143 // Number is finite.