1#![allow(clippy::redundant_closure_call, clippy::derive_partial_eq_without_eq)]23mod expr;4use std::{cmp::Ordering, fmt, ops::Deref};56pub use expr::*;7use jrsonnet_gcmodule::Acyclic;8pub use jrsonnet_interner::IStr;9pub mod function;10mod location;11mod source;12pub mod unescape;13pub mod visit;1415pub use location::CodeLocation;16pub use source::{17 Source, SourceDefaultIgnoreJpath, SourceDirectory, SourceFifo, SourceFile, SourcePath,18 SourcePathT, SourceUrl, SourceVirtual,19};20212223#[expect(clippy::cast_precision_loss, reason = "checked to not overflow")]24pub const MAX_SAFE_INTEGER: f64 = ((1u64 << (f64::MANTISSA_DIGITS)) - 1) as f64;25#[expect(clippy::cast_precision_loss, reason = "checked to not overflow")]26pub const MIN_SAFE_INTEGER: f64 = (-((1i64 << (f64::MANTISSA_DIGITS)) - 1)) as f64;27282930#[derive(Acyclic, Clone, Copy)]31pub struct NumValue(f64);32impl NumValue {33 34 pub fn new(v: f64) -> Option<Self> {35 if !v.is_finite() {36 return None;37 }38 Some(Self(v))39 }40 #[inline]41 pub const fn get(&self) -> f64 {42 self.043 }44 pub fn truncate_for_bitwise(self) -> Result<i64, ConvertNumValueError> {45 if self.0 < MIN_SAFE_INTEGER || self.0 > MAX_SAFE_INTEGER {46 return Err(ConvertNumValueError::BitwiseSafeRange);47 }48 #[expect(clippy::cast_possible_truncation, reason = "intended")]49 Ok(self.0 as i64)50 }51}52impl PartialEq for NumValue {53 fn eq(&self, other: &Self) -> bool {54 self.0 == other.055 }56}57impl Eq for NumValue {}58impl Ord for NumValue {59 #[inline]60 fn cmp(&self, other: &Self) -> Ordering {61 62 63 unsafe { self.0.partial_cmp(&other.0).unwrap_unchecked() }64 }65}66impl PartialOrd for NumValue {67 #[inline]68 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {69 Some(self.cmp(other))70 }71}72impl fmt::Debug for NumValue {73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {74 fmt::Debug::fmt(&self.0, f)75 }76}77impl fmt::Display for NumValue {78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {79 fmt::Display::fmt(&self.0, f)80 }81}82impl Deref for NumValue {83 type Target = f64;8485 #[inline]86 fn deref(&self) -> &Self::Target {87 &self.088 }89}90macro_rules! impl_num {91 ($($ty:ty),+) => {$(92 impl From<$ty> for NumValue {93 #[inline]94 fn from(value: $ty) -> Self {95 Self(value.into())96 }97 }98 )+};99}100impl_num!(i8, u8, i16, u16, i32, u32);101102#[derive(Clone, Copy, Debug, thiserror::Error, Acyclic)]103pub enum ConvertNumValueError {104 #[error("overflow")]105 Overflow,106 #[error("underflow")]107 Underflow,108 #[error("non-finite")]109 NonFinite,110 #[error("float out of safe int range")]111 BitwiseSafeRange,112}113114macro_rules! impl_try_num {115 ($($ty:ty),+) => {$(116 impl TryFrom<$ty> for NumValue {117 type Error = ConvertNumValueError;118 #[inline]119 fn try_from(value: $ty) -> Result<Self, ConvertNumValueError> {120 #[expect(clippy::cast_precision_loss, reason = "precision loss is explicitly handled")]121 let value = value as f64;122 if value < MIN_SAFE_INTEGER {123 return Err(ConvertNumValueError::Underflow)124 } else if value > MAX_SAFE_INTEGER {125 return Err(ConvertNumValueError::Overflow)126 }127 128 Ok(Self(value))129 }130 }131 )+};132}133impl_try_num!(usize, isize, i64, u64);134135impl TryFrom<f64> for NumValue {136 type Error = ConvertNumValueError;137138 #[inline]139 fn try_from(value: f64) -> Result<Self, Self::Error> {140 Self::new(value).ok_or(ConvertNumValueError::NonFinite)141 }142}143impl TryFrom<f32> for NumValue {144 type Error = ConvertNumValueError;145146 #[inline]147 fn try_from(value: f32) -> Result<Self, Self::Error> {148 Self::new(f64::from(value)).ok_or(ConvertNumValueError::NonFinite)149 }150}