difftreelog
style fix clippy warnings
in: master
36 files changed
bindings/jsonnet/src/native.rsdiffbeforeafterboth43 }43 }44 n_args.push(None);44 n_args.push(None);45 let mut success = 1;45 let mut success = 1;46 let v = unsafe { (self.cb)(self.ctx, n_args.as_ptr().cast(), &mut success) };46 let v = unsafe { (self.cb)(self.ctx, n_args.as_ptr().cast(), &raw mut success) };47 let v = unsafe { *Box::from_raw(v) };47 let v = unsafe { *Box::from_raw(v) };48 if success == 1 {48 if success == 1 {49 Ok(v)49 Ok(v)crates/jrsonnet-cli/src/tla.rsdiffbeforeafterboth778#[derive(Parser)]8#[derive(Parser)]9#[clap(next_help_heading = "TOP LEVEL ARGUMENTS")]9#[clap(next_help_heading = "TOP LEVEL ARGUMENTS")]10#[allow(clippy::struct_field_names)]10pub struct TlaOpts {11pub struct TlaOpts {11 /// Add top level string argument.12 /// Add top level string argument.12 /// Top level arguments will be passed to function before manifestification stage.13 /// Top level arguments will be passed to function before manifestification stage.crates/jrsonnet-evaluator/src/arr/mod.rsdiffbeforeafterboth77 let i = i?;77 let i = i?;78 if filter(&i)? {78 if filter(&i)? {79 out.push(i);79 out.push(i);80 };80 }81 }81 }82 Ok(Self::eager(out))82 Ok(Self::eager(out))83 }83 }crates/jrsonnet-evaluator/src/arr/spec.rsdiffbeforeafterboth38}38}39impl ArrayLike for SliceArray {39impl ArrayLike for SliceArray {40 fn len(&self) -> usize {40 fn len(&self) -> usize {41 ((self.to - self.from + self.step - 1) / self.step) as usize41 (self.to - self.from).div_ceil(self.step) as usize42 }42 }434344 fn get(&self, index: usize) -> Result<Option<Val>> {44 fn get(&self, index: usize) -> Result<Option<Val>> {139 ArrayThunk::Errored(e) => return Err(e.clone()),139 ArrayThunk::Errored(e) => return Err(e.clone()),140 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),140 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),141 ArrayThunk::Waiting => {}141 ArrayThunk::Waiting => {}142 };142 }143143144 let ArrayThunk::Waiting =144 let ArrayThunk::Waiting =145 replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)145 replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)158 Ok(Some(new_value))158 Ok(Some(new_value))159 }159 }160 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {160 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {161 #[derive(Trace)]162 struct ExprArrThunk {163 expr: ExprArray,164 index: usize,165 }166 impl ThunkValue for ExprArrThunk {167 type Output = Val;168169 fn get(&self) -> Result<Self::Output> {170 self.expr171 .get(self.index)172 .transpose()173 .expect("index checked")174 }175 }176161 if index >= self.len() {177 if index >= self.len() {162 return None;178 return None;165 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),181 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),166 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),182 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),167 ArrayThunk::Waiting | ArrayThunk::Pending => {}183 ArrayThunk::Waiting | ArrayThunk::Pending => {}168 };184 }169170 #[derive(Trace)]171 struct ExprArrThunk {172 expr: ExprArray,173 index: usize,174 }175 impl ThunkValue for ExprArrThunk {176 type Output = Val;177178 fn get(&self) -> Result<Self::Output> {179 self.expr180 .get(self.index)181 .transpose()182 .expect("index checked")183 }184 }185185186 Some(Thunk::new(ExprArrThunk {186 Some(Thunk::new(ExprArrThunk {187 expr: self.clone(),187 expr: self.clone(),441 ArrayThunk::Errored(e) => return Err(e.clone()),441 ArrayThunk::Errored(e) => return Err(e.clone()),442 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),442 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),443 ArrayThunk::Waiting => {}443 ArrayThunk::Waiting => {}444 };444 }445445446 let ArrayThunk::Waiting =446 let ArrayThunk::Waiting =447 replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)447 replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)467 Ok(Some(new_value))467 Ok(Some(new_value))468 }468 }469 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {469 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {470 #[derive(Trace)]471 struct MappedArrayThunk<const WITH_INDEX: bool> {472 arr: MappedArray<WITH_INDEX>,473 index: usize,474 }475 impl<const WITH_INDEX: bool> ThunkValue for MappedArrayThunk<WITH_INDEX> {476 type Output = Val;477478 fn get(&self) -> Result<Self::Output> {479 self.arr.get(self.index).transpose().expect("index checked")480 }481 }482470 if index >= self.len() {483 if index >= self.len() {471 return None;484 return None;474 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),487 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),475 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),488 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),476 ArrayThunk::Waiting | ArrayThunk::Pending => {}489 ArrayThunk::Waiting | ArrayThunk::Pending => {}477 };490 }478479 #[derive(Trace)]480 struct MappedArrayThunk<const WITH_INDEX: bool> {481 arr: MappedArray<WITH_INDEX>,482 index: usize,483 }484 impl<const WITH_INDEX: bool> ThunkValue for MappedArrayThunk<WITH_INDEX> {485 type Output = Val;486487 fn get(&self) -> Result<Self::Output> {488 self.arr.get(self.index).transpose().expect("index checked")489 }490 }491491492 Some(Thunk::new(MappedArrayThunk {492 Some(Thunk::new(MappedArrayThunk {493 arr: self.clone(),493 arr: self.clone(),crates/jrsonnet-evaluator/src/async_import.rsdiffbeforeafterboth21// Visits all nodes, trying to find import statements21// Visits all nodes, trying to find import statements22#[allow(clippy::too_many_lines)]22#[allow(clippy::too_many_lines)]23pub fn find_imports(expr: &Spanned<Expr>, out: &mut FoundImports) {23pub fn find_imports(expr: &Spanned<Expr>, out: &mut FoundImports) {24 #[allow(unused_variables, clippy::needless_pass_by_ref_mut)]24 fn in_destruct(dest: &Destruct, #[allow(unused_variables)] out: &mut FoundImports) {25 fn in_destruct(dest: &Destruct, out: &mut FoundImports) {25 match dest {26 match dest {26 #[cfg(feature = "exp-destruct")]27 #[cfg(feature = "exp-destruct")]27 Destruct::Array {28 Destruct::Array {296 .downcast_ref::<ResolvedImportResolver>()297 .downcast_ref::<ResolvedImportResolver>()297 .expect("for async imports, import_resolver should be set to ResolvedImportResolver");298 .expect("for async imports, import_resolver should be set to ResolvedImportResolver");298299 let mut resolved_map = resolved.resolved.borrow_mut();300299301 let mut queue = vec![Job::LoadFile {300 let mut queue = vec![Job::LoadFile {302 path: handler.resolve_from_default(path).await?,301 path: handler.resolve_from_default(path).await?,340 }339 }341 }340 }342 Job::ResolveImport { from, import } => {341 Job::ResolveImport { from, import } => {342 {343 let mut resolved_map = resolved.resolved.borrow_mut();343 if let Some((resolved, expression)) =344 if let Some((resolved, expression)) =344 resolved_map.get_mut(&(from.clone(), import.path.clone()))345 resolved_map.get_mut(&(from.clone(), import.path.clone()))345 {346 {349 }350 }350 continue;351 continue;351 }352 }353 }352 let resolved = handler.resolve_from(&from, &import.path).await?;354 let resolved = handler.resolve_from(&from, &import.path).await?;353 queue.push(Job::LoadFile {355 queue.push(Job::LoadFile {354 path: resolved,356 path: resolved,crates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth1use std::{collections::HashMap, hash::BuildHasher};21use jrsonnet_interner::IStr;3use jrsonnet_interner::IStr;2use jrsonnet_parser::{BindSpec, Destruct};4use jrsonnet_parser::{BindSpec, Destruct};3use rustc_hash::FxHashMap;455use crate::{6use crate::{6 bail,7 bail,101111#[allow(clippy::too_many_lines)]12#[allow(clippy::too_many_lines)]12#[allow(unused_variables)]13#[allow(unused_variables)]13pub fn destruct(14pub fn destruct<H: BuildHasher>(14 d: &Destruct,15 d: &Destruct,15 parent: Thunk<Val>,16 parent: Thunk<Val>,16 fctx: Pending<Context>,17 fctx: Pending<Context>,17 new_bindings: &mut FxHashMap<IStr, Thunk<Val>>,18 new_bindings: &mut HashMap<IStr, Thunk<Val>, H>,18) -> Result<()> {19) -> Result<()> {19 match d {20 match d {20 Destruct::Full(v) => {21 Destruct::Full(v) => {159 Ok(())160 Ok(())160}161}161162162pub fn evaluate_dest(163pub fn evaluate_dest<H: BuildHasher>(163 d: &BindSpec,164 d: &BindSpec,164 fctx: Pending<Context>,165 fctx: Pending<Context>,165 new_bindings: &mut FxHashMap<IStr, Thunk<Val>>,166 new_bindings: &mut HashMap<IStr, Thunk<Val>, H>,166) -> Result<()> {167) -> Result<()> {167 match d {168 match d {168 BindSpec::Field { into, value } => {169 BindSpec::Field { into, value } => {crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth291 let uctx = CachedUnbound::new(evaluate_object_locals(ctx.clone(), locals));291 let uctx = CachedUnbound::new(evaluate_object_locals(ctx.clone(), locals));292292293 for field in &members.fields {293 for field in &members.fields {294 evaluate_field_member(&mut builder, ctx.clone(), uctx.clone(), &field)?;294 evaluate_field_member(&mut builder, ctx.clone(), uctx.clone(), field)?;295 }295 }296296297 if !members.asserts.is_empty() {297 if !members.asserts.is_empty() {304 fn run(&self, sup_this: SupThis) -> Result<()> {304 fn run(&self, sup_this: SupThis) -> Result<()> {305 let ctx = self.uctx.bind(sup_this)?;305 let ctx = self.uctx.bind(sup_this)?;306 for assert in &*self.asserts {306 for assert in &*self.asserts {307 evaluate_assert(ctx.clone(), &assert)?;307 evaluate_assert(ctx.clone(), assert)?;308 }308 }309 Ok(())309 Ok(())310 }310 }311 }311 }312 builder.assert(ObjectAssert {312 builder.assert(ObjectAssert {313 uctx: uctx.clone(),313 uctx,314 asserts: members.asserts.clone(),314 asserts: members.asserts.clone(),315 });315 });316 }316 }567 evaluate_dest(b, fctx.clone(), &mut new_bindings)?;567 evaluate_dest(b, fctx.clone(), &mut new_bindings)?;568 }568 }569 let ctx = ctx.extend_bindings(new_bindings).into_future(fctx);569 let ctx = ctx.extend_bindings(new_bindings).into_future(fctx);570 evaluate(ctx, &returned.clone())?570 evaluate(ctx, returned)?571 }571 }572 Arr(items) => {572 Arr(items) => {573 if items.is_empty() {573 if items.is_empty() {crates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth95 // string format95 // string format96 (Str(_), _) => false,96 (Str(_), _) => false,979798 (_, Num(b)) => return **b == 0.,98 (_, Num(b)) => **b == 0.,99 #[cfg(feature = "exp-bigint")]99 #[cfg(feature = "exp-bigint")]100 (_, BigInt(b)) => return **b == num_bigint::BigInt::ZERO,100 (_, BigInt(b)) => **b == num_bigint::BigInt::ZERO,101101102 // something else102 // something else103 _ => false,103 _ => false,crates/jrsonnet-evaluator/src/function/arglike.rsdiffbeforeafterboth239 }239 }240240241 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {241 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {242 for (name, _) in self {242 for name in self.keys() {243 handler(name);243 handler(name);244 }244 }245 }245 }crates/jrsonnet-evaluator/src/function/parse.rsdiffbeforeafterboth1use std::mem::replace;23use jrsonnet_parser::{1use jrsonnet_parser::{4 function::{FunctionSignature, ParamName},2 function::{FunctionSignature, ParamName},87 }85 }888689 destruct(87 destruct(90 &into,88 into,91 {89 {92 let ctx = fctx.clone();90 let ctx = fctx.clone();93 let name = into.name();91 let name = into.name();97 fctx.clone(),95 fctx.clone(),98 &mut defaults,96 &mut defaults,99 )?;97 )?;100 if !into.name().is_anonymous() {98 if into.name().is_named() {101 filled_named += 1;99 filled_named += 1;102 } else {100 } else {103 filled_positionals += 1;101 filled_positionals += 1;165 .iter()163 .iter()166 .position(|p| p.name() == name)164 .position(|p| p.name() == name)167 .ok_or_else(|| UnknownFunctionParameter(name.clone()))?;165 .ok_or_else(|| UnknownFunctionParameter(name.clone()))?;168 if replace(&mut passed_args[id], Some(arg)).is_some() {166 if passed_args[id].replace(arg).is_some() {169 bail!(BindingParameterASecondTime(name.clone()));167 bail!(BindingParameterASecondTime(name.clone()));170 }168 }171 filled_args += 1;169 filled_args += 1;230 let params = params.clone();228 let params = params.clone();231 Thunk!(move || Err(FunctionParameterNotBoundInCall(229 Thunk!(move || Err(FunctionParameterNotBoundInCall(232 param_name,230 param_name,233 params.signature.clone()231 params.signature234 )232 )235 .into()))233 .into()))236 },234 },crates/jrsonnet-evaluator/src/gc.rsdiffbeforeafterboth1#![allow(2 clippy::implicit_hasher,3 reason = "those methods exist exactly because with_capacity is only present for default BuildHasher"4)]51/// Macros to help deal with Gc6/// Macros to help deal with Gc2use jrsonnet_gcmodule::Trace;7use jrsonnet_gcmodule::Trace;8}13}9impl<V> WithCapacityExt for FxHashSet<V> {14impl<V> WithCapacityExt for FxHashSet<V> {10 fn with_capacity(capacity: usize) -> Self {15 fn with_capacity(capacity: usize) -> Self {11 Self::with_capacity_and_hasher(capacity, FxBuildHasher::default())16 Self::with_capacity_and_hasher(capacity, FxBuildHasher)12 }17 }131814 fn new() -> Self {19 fn new() -> Self {15 Self::with_hasher(FxBuildHasher::default())20 Self::with_hasher(FxBuildHasher)16 }21 }17}22}18impl<K, V> WithCapacityExt for FxHashMap<K, V> {23impl<K, V> WithCapacityExt for FxHashMap<K, V> {19 fn with_capacity(capacity: usize) -> Self {24 fn with_capacity(capacity: usize) -> Self {20 Self::with_capacity_and_hasher(capacity, FxBuildHasher::default())25 Self::with_capacity_and_hasher(capacity, FxBuildHasher)21 }26 }222723 fn new() -> Self {28 fn new() -> Self {24 Self::with_hasher(FxBuildHasher::default())29 Self::with_hasher(FxBuildHasher)25 }30 }26}31}2732crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth367 let res = evaluate(self.create_default_context(file_name), &parsed);367 let res = evaluate(self.create_default_context(file_name), &parsed);368368369 let mut file_cache = self.file_cache();369 let mut file_cache = self.file_cache();370 let mut file = file_cache.entry(path.clone());370 let mut file = file_cache.entry(path);371371372 let Entry::Occupied(file) = &mut file else {372 let Entry::Occupied(file) = &mut file else {373 unreachable!("this file was just here")373 unreachable!("this file was just here")crates/jrsonnet-evaluator/src/manifest.rsdiffbeforeafterboth240 }240 }241 ToString if i != 0 => buf.push(' '),241 ToString if i != 0 => buf.push(' '),242 Minify | ToString => {}242 Minify | ToString => {}243 };243 }244244245 in_description_frame(245 in_description_frame(246 || format!("elem <{i}> manifestification"),246 || format!("elem <{i}> manifestification"),335 buf.push('}');335 buf.push('}');336 }336 }337 Val::Func(_) => bail!("tried to manifest function"),337 Val::Func(_) => bail!("tried to manifest function"),338 };338 }339 Ok(())339 Ok(())340}340}341341crates/jrsonnet-evaluator/src/map.rsdiffbeforeafterboth161617impl LayeredHashMap {17impl LayeredHashMap {18 pub fn iter_keys(self, mut handler: impl FnMut(IStr)) {18 pub fn iter_keys(self, mut handler: impl FnMut(IStr)) {19 for (k, _) in &self.0.current {19 for k in self.0.current.keys() {20 handler(k.clone());20 handler(k.clone());21 }21 }22 if let Some(parent) = self.0.parent.clone() {22 if let Some(parent) = self.0.parent.clone() {474748 pub fn contains_key(&self, key: &IStr) -> bool {48 pub fn contains_key(&self, key: &IStr) -> bool {49 (self.0).current.contains_key(key)49 (self.0).current.contains_key(key)50 || self50 || self.0.parent.as_ref().is_some_and(|p| p.contains_key(key))51 .052 .parent53 .as_ref()54 .map_or(false, |p| p.contains_key(key))55 }51 }56}52}5753crates/jrsonnet-evaluator/src/obj/mod.rsdiffbeforeafterboth1use std::{1use std::{2 any::Any,2 any::Any,3 cell::{Cell, RefCell},3 cell::{Cell, RefCell},4 clone::Clone,4 collections::hash_map::Entry,5 collections::hash_map::Entry,5 fmt::{self, Debug},6 fmt::{self, Debug},6 hash::{Hash, Hasher},7 hash::{Hash, Hasher},272273273impl ObjValue {274impl ObjValue {274 pub fn empty() -> Self {275 pub fn empty() -> Self {275 EMPTY_OBJ.with(|v| v.clone())276 EMPTY_OBJ.with(Clone::clone)276 }277 }277 pub fn is_empty(&self) -> bool {278 pub fn is_empty(&self) -> bool {278 self.0.cores.is_empty() || self.len() == 0279 self.0.cores.is_empty() || self.len() == 0306 return Ok(GetFor::NotFound);307 return Ok(GetFor::NotFound);307 }308 }308 let v = self.this.get_idx(key, self.sup)?;309 let v = self.this.get_idx(key, self.sup)?;309 Ok(v.map_or(GetFor::NotFound, |v| GetFor::Final(v)))310 Ok(v.map_or(GetFor::NotFound, GetFor::Final))310 }311 }311312312 fn field_visibility_core(&self, field: IStr) -> FieldVisibility {313 fn field_visibility_core(&self, field: IStr) -> FieldVisibility {313 match self.this.field_visibility_idx(field, self.sup) {314 self.this315 .field_visibility_idx(field, self.sup)314 Some(c) => FieldVisibility::Found(c),316 .map_or(FieldVisibility::NotFound, FieldVisibility::Found)315 None => FieldVisibility::NotFound,316 }317 }317 }318318319 fn run_assertions_core(&self, _sup_this: SupThis) -> Result<()> {319 fn run_assertions_core(&self, _sup_this: SupThis) -> Result<()> {crates/jrsonnet-evaluator/src/obj/oop.rsdiffbeforeafterboth1use std::cell::Cell;1use std::cell::{Cell, RefCell};2use std::ops::ControlFlow;2use std::ops::ControlFlow;3use std::{fmt, mem};3use std::{fmt, mem};44105105106 fn run_assertions_core(&self, sup_this: SupThis) -> Result<()> {106 fn run_assertions_core(&self, sup_this: SupThis) -> Result<()> {107 if let Some(assertion) = &self.assertion {107 if let Some(assertion) = &self.assertion {108 assertion.0.run(sup_this.clone())?;108 assertion.0.run(sup_this)?;109 }109 }110 Ok(())110 Ok(())111 }111 }196 ObjValue(Cc::new(ObjValueInner {196 ObjValue(Cc::new(ObjValueInner {197 cores: self.sup,197 cores: self.sup,198 assertions_ran: Cell::new(false),198 assertions_ran: Cell::new(false),199 value_cache: Default::default(),199 value_cache: RefCell::default(),200 }))200 }))201 }201 }202}202}crates/jrsonnet-evaluator/src/stack.rsdiffbeforeafterboth17 }17 }18}18}19#[cfg(not(nightly))]19#[cfg(not(nightly))]20#[allow(dead_code)]20type NightlyLocalKey<T> = std::thread::LocalKey<T>;21type NightlyLocalKey<T> = std::thread::LocalKey<T>;212222#[cfg(nightly)]23#[cfg(nightly)]60pub struct StackDepthGuard(PhantomData<()>);61pub struct StackDepthGuard(PhantomData<()>);61impl Drop for StackDepthGuard {62impl Drop for StackDepthGuard {62 fn drop(&mut self) {63 fn drop(&mut self) {63 STACK_LIMIT.with(|limit| limit.current_depth.set(limit.current_depth.get() - 1))64 STACK_LIMIT.with(|limit| limit.current_depth.set(limit.current_depth.get() - 1));64 }65 }65}66}6667crates/jrsonnet-evaluator/src/stdlib/format.rsdiffbeforeafterboth297const NUMBERS: &[u8] = b"0123456789abcdefghijklmnopqrstuvwxyz";297const NUMBERS: &[u8] = b"0123456789abcdefghijklmnopqrstuvwxyz";298298299#[inline]299#[inline]300#[allow(clippy::fn_params_excessive_bools)]300pub fn render_integer(301pub fn render_integer(301 out: &mut String,302 out: &mut String,302 neg: bool,303 neg: bool,330331331 let pref_len = zero_prefix.len() as u16;332 let pref_len = zero_prefix.len() as u16;332 let zp2 = zp333 let zp2 = zp333 .saturating_sub(if !prefix_in_padding { pref_len } else { 0 })334 .saturating_sub(if prefix_in_padding { 0 } else { pref_len })334 .max(precision)335 .max(precision)335 .saturating_sub(if prefix_in_padding { pref_len } else { 0 } + digits.len() as u16);336 .saturating_sub(if prefix_in_padding { pref_len } else { 0 } + digits.len() as u16);336337369 out, neg, iv, padding, precision, blank, sign, 10, "", false, false,370 out, neg, iv, padding, precision, blank, sign, 10, "", false, false,370 );371 );371}372}373#[allow(clippy::fn_params_excessive_bools)]372pub fn render_octal(374pub fn render_octal(373 out: &mut String,375 out: &mut String,374 neg: bool,376 neg: bool,439 // Note that it can also be equal to 10**prec and we'll need to carry441 // Note that it can also be equal to 10**prec and we'll need to carry440 // over to the wholes. We operate on the absolute numbers, so that we442 // over to the wholes. We operate on the absolute numbers, so that we441 // don't have trouble with the rounding direction.443 // don't have trouble with the rounding direction.442 let denominator = 10.0f64.powi(precision as i32);444 let denominator = 10.0f64.powi(i32::from(precision));443 let numerator = n.abs() * denominator + 0.5;445 let numerator = n.abs().mul_add(denominator, 0.5);444 let whole = (numerator / denominator).floor();446 let whole = (numerator / denominator).floor();445 let frac = numerator.floor() % denominator;447 let frac = numerator.floor() % denominator;446448611 } else {613 } else {612 value.abs().log10().floor()614 value.abs().log10().floor()613 };615 };614 if exponent < -4.0 || exponent >= fpprec as f64 {616 if exponent < -4.0 || exponent >= f64::from(fpprec) {615 render_float_sci(617 render_float_sci(616 &mut tmp_out,618 &mut tmp_out,617 value,619 value,661 }663 }662 },664 },663 ConvTypeV::Percent => tmp_out.push('%'),665 ConvTypeV::Percent => tmp_out.push('%'),664 };666 }665667666 let padding = width.saturating_sub(tmp_out.len() as u16);668 let padding = width.saturating_sub(tmp_out.len() as u16);667669crates/jrsonnet-evaluator/src/tla.rsdiffbeforeafterboth1use std::{collections::HashMap, hash::BuildHasher};21use jrsonnet_interner::IStr;3use jrsonnet_interner::IStr;2use jrsonnet_parser::Source;4use jrsonnet_parser::Source;3use rustc_hash::FxHashMap;455use crate::{6use crate::{6 function::{CallLocation, TlaArg},7 function::{CallLocation, TlaArg},7 in_description_frame, with_state, Result, Val,8 in_description_frame, with_state, Result, Val,8};9};91010pub fn apply_tla(args: &FxHashMap<IStr, TlaArg>, val: Val) -> Result<Val> {11pub fn apply_tla<H: BuildHasher>(args: &HashMap<IStr, TlaArg, H>, val: Val) -> Result<Val> {11 Ok(if let Val::Func(func) = val {12 Ok(if let Val::Func(func) = val {12 in_description_frame(13 in_description_frame(13 || "during TLA call".to_owned(),14 || "during TLA call".to_owned(),crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth462 };462 };463 if let Some(bytes) = a.as_any().downcast_ref::<BytesArray>() {463 if let Some(bytes) = a.as_any().downcast_ref::<BytesArray>() {464 return Ok(bytes.0.as_slice().into());464 return Ok(bytes.0.as_slice().into());465 };465 }466 <Self as Typed>::TYPE.check(&value)?;466 <Self as Typed>::TYPE.check(&value)?;467 // Any::downcast_ref::<ByteArray>(&a);467 // Any::downcast_ref::<ByteArray>(&a);468 let mut out = Vec::with_capacity(a.len());468 let mut out = Vec::with_capacity(a.len());crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth65 MemoizedClusureThunkInner::Errored(e) => return Err(e.clone()),65 MemoizedClusureThunkInner::Errored(e) => return Err(e.clone()),66 MemoizedClusureThunkInner::Pending => return Err(InfiniteRecursionDetected.into()),66 MemoizedClusureThunkInner::Pending => return Err(InfiniteRecursionDetected.into()),67 MemoizedClusureThunkInner::Waiting { .. } => (),67 MemoizedClusureThunkInner::Waiting { .. } => (),68 };68 }69 let MemoizedClusureThunkInner::Waiting { env, closure } = replace(69 let MemoizedClusureThunkInner::Waiting { env, closure } = replace(70 &mut *self.0.borrow_mut(),70 &mut *self.0.borrow_mut(),71 MemoizedClusureThunkInner::Pending,71 MemoizedClusureThunkInner::Pending,288 Self::Str(s) => {288 Self::Str(s) => {289 let mut computed_len = None;289 let mut computed_len = None;290 let mut get_len = || {290 let mut get_len = || {291 computed_len.map_or_else(291 computed_len.unwrap_or_else(|| {292 || {293 let len = s.chars().count();292 let len = s.chars().count();294 let _ = computed_len.insert(len);293 let _ = computed_len.insert(len);295 len294 len296 },295 })297 |len| len,298 )299 };296 };300 let mut get_idx = |pos: Option<i32>, default| {297 let mut get_idx = |pos: Option<i32>, default| {446 pub const fn get(&self) -> f64 {443 pub const fn get(&self) -> f64 {447 self.0444 self.0448 }445 }449 pub(crate) fn truncate_for_bitwise(&self) -> Result<i64> {446 pub(crate) fn truncate_for_bitwise(self) -> Result<i64> {450 if self.0 < MIN_SAFE_INTEGER || self.0 > MAX_SAFE_INTEGER {447 if self.0 < MIN_SAFE_INTEGER || self.0 > MAX_SAFE_INTEGER {451 bail!("numberic value outside of safe integer range for bitwise operation");448 bail!("numberic value outside of safe integer range for bitwise operation");452 }449 }crates/jrsonnet-interner/src/lib.rsdiffbeforeafterboth227type PoolMap = HashMap<Inner, (), FxBuildHasher>;227type PoolMap = HashMap<Inner, (), FxBuildHasher>;228228229thread_local! {229thread_local! {230 static POOL: RefCell<PoolMap> = RefCell::new(HashMap::with_capacity_and_hasher(200, FxBuildHasher::default()));230 static POOL: RefCell<PoolMap> = RefCell::new(HashMap::with_capacity_and_hasher(200, FxBuildHasher));231}231}232232233/// Utils for embedding jrsonnet in non-rust.234///233/// Jrsonnet golang bindings require that it is possible to move jsonnet235/// Jrsonnet golang bindings require that it is possible to move jsonnet234/// VM between OS threads, and this is not possible due to usage of236/// VM between OS threads, and this is not possible due to usage of235/// `thread_local`. Instead, there is two methods added, one should be237/// `thread_local`. Instead, there is two methods added, one should becrates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth127 Default(Expr),127 Default(Expr),128}128}129129130#[allow(clippy::large_enum_variant, reason = "this macro is not that hot for it to matter")]130enum ArgInfo {131enum ArgInfo {131 Normal {132 Normal {132 ty: Box<Type>,133 ty: Box<Type>,crates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth166 pub fn len(&self) -> usize {166 pub fn len(&self) -> usize {167 self.exprs.len()167 self.exprs.len()168 }168 }169 pub fn is_empty(&self) -> bool {170 self.exprs.is_empty()171 }172169 pub fn binds_len(&self) -> usize {173 pub fn binds_len(&self) -> usize {170 self.binds_len174 self.binds_lencrates/jrsonnet-stdlib/src/arrays.rsdiffbeforeafterboth98 for c in str.chars() {98 for c in str.chars() {99 match func(Either2::A(c.to_string()))? {99 match func(Either2::A(c.to_string()))? {100 Val::Str(o) => write!(out, "{o}").unwrap(),100 Val::Str(o) => write!(out, "{o}").unwrap(),101 Val::Null => continue,101 Val::Null => {},102 _ => bail!("in std.join all items should be strings"),102 _ => bail!("in std.join all items should be strings"),103 };103 }104 }104 }105 Ok(IndexableVal::Str(out.into()))105 Ok(IndexableVal::Str(out.into()))106 }106 }114 out.push(oe?);114 out.push(oe?);115 }115 }116 }116 }117 Val::Null => continue,117 Val::Null => {},118 _ => bail!("in std.join all items should be arrays"),118 _ => bail!("in std.join all items should be arrays"),119 };119 }120 }120 }121 Ok(IndexableVal::Arr(out.into()))121 Ok(IndexableVal::Arr(out.into()))122 }122 }205 out.push(item?);205 out.push(item?);206 }206 }207 } else if matches!(item, Val::Null) {207 } else if matches!(item, Val::Null) {208 continue;209 } else {208 } else {210 bail!("in std.join all items should be arrays");209 bail!("in std.join all items should be arrays");211 }210 }226 first = false;225 first = false;227 write!(out, "{item}").unwrap();226 write!(out, "{item}").unwrap();228 } else if matches!(item, Val::Null) {227 } else if matches!(item, Val::Null) {229 continue;230 } else {228 } else {231 bail!("in std.join all items should be strings");229 bail!("in std.join all items should be strings");232 }230 }crates/jrsonnet-stdlib/src/manifest/xml.rsdiffbeforeafterboth46 };46 };47 if arr.is_empty() {47 if arr.is_empty() {48 bail!("JSONML value should have tag (array length should be >=1)");48 bail!("JSONML value should have tag (array length should be >=1)");49 };49 }50 let tag = String::from_untyped(50 let tag = String::from_untyped(51 arr.get(0)51 arr.get(0)52 .description("getting JSONML tag")?52 .description("getting JSONML tag")?crates/jrsonnet-stdlib/src/manifest/yaml.rsdiffbeforeafterboth90 RESERVED.iter().any(|k| key.eq_ignore_ascii_case(k))90 RESERVED.iter().any(|k| key.eq_ignore_ascii_case(k))91 }91 }929293 #[allow(clippy::if_same_then_else)]93 // Check for unsafe characters94 // Check for unsafe characters94 if !key95 if !key95 .chars()96 .chars()98 return false;99 return false;99 }100 }100 // Check for reserved words101 // Check for reserved words101 if is_reserved(key) {102 else if is_reserved(key) {102 return false;103 return false;103 }104 }104 // Check for timestamp values. Since spaces and colons are already forbidden,105 // Check for timestamp values. Since spaces and colons are already forbidden,107 // - all characters match [0-9\-]108 // - all characters match [0-9\-]108 // - has exactly 2 dashes109 // - has exactly 2 dashes109 // are considered dates.110 // are considered dates.110 if key.chars().all(|v| matches!(v, '0'..='9' | '-')) && count_char(key, '-') == 2 {111 else if key.chars().all(|v| matches!(v, '0'..='9' | '-')) && count_char(key, '-') == 2 {111 return false;112 return false;112 }113 }113 // Check for integers. Keys that meet all of the following:114 // Check for integers. Keys that meet all of the following:crates/jrsonnet-stdlib/src/misc.rsdiffbeforeafterboth172 let Some(patch) = patch.as_obj() else {172 let Some(patch) = patch.as_obj() else {173 return Ok(patch);173 return Ok(patch);174 };174 };175 let target = target.as_obj().unwrap_or_else(|| ObjValue::empty());175 let target = target.as_obj().unwrap_or_else(ObjValue::empty);176 let target_fields = target176 let target_fields = target177 .fields(177 .fields(178 // FIXME: Makes no sense to preserve order for BTreeSet, it would be better to use IndexSet here?178 // FIXME: Makes no sense to preserve order for BTreeSet, it would be better to use IndexSet here?crates/jrsonnet-stdlib/src/sets.rsdiffbeforeafterboth21 let x = keyF(x)?;21 let x = keyF(x)?;222223 while low < high {23 while low < high {24 let middle = (high + low) / 2;24 let middle = usize::midpoint(high, low);25 let comp = keyF(arr.get_lazy(middle).expect("in bounds"))?;25 let comp = keyF(arr.get_lazy(middle).expect("in bounds"))?;26 match evaluate_compare_op(&comp, &x, BinaryOpType::Lt)? {26 match evaluate_compare_op(&comp, &x, BinaryOpType::Lt)? {27 Ordering::Less => low = middle + 1,27 Ordering::Less => low = middle + 1,66 bv = b.next();66 bv = b.next();67 bk = bv.map(keyF).transpose()?;67 bk = bv.map(keyF).transpose()?;68 }68 }69 };69 }70 }70 }71 Ok(ArrValue::lazy(out))71 Ok(ArrValue::lazy(out))72}72}106 bv = b.next();106 bv = b.next();107 bk = bv.map(keyF).transpose()?;107 bk = bv.map(keyF).transpose()?;108 }108 }109 };109 }110 }110 }111 while let Some(_ac) = &ak {111 while let Some(_ac) = &ak {112 // In a, but not in b112 // In a, but not in b154 bv = b.next();154 bv = b.next();155 bk = bv.clone().map(keyF).transpose()?;155 bk = bv.clone().map(keyF).transpose()?;156 }156 }157 };157 }158 }158 }159 // a.len() > b.len()159 // a.len() > b.len()160 while let Some(_ac) = &ak {160 while let Some(_ac) = &ak {crates/jrsonnet-stdlib/src/sort.rsdiffbeforeafterboth66 return Err(err);66 return Err(err);67 }67 }68 }68 }69 };69 }70 Ok(values)70 Ok(values)71}71}7272107 return Err(err);107 return Err(err);108 }108 }109 }109 }110 };110 }111 Ok(vk.into_iter().map(|v| v.0).collect())111 Ok(vk.into_iter().map(|v| v.0).collect())112}112}113113204 }204 }205}205}206206207fn eval_keyf(val: Val, key_f: &Option<FuncVal>) -> Result<Val> {207fn eval_keyf(val: Val, key_f: Option<&FuncVal>) -> Result<Val> {208 if let Some(key_f) = key_f {208 if let Some(key_f) = key_f {209 key_f.evaluate_simple(&(val,), false)209 key_f.evaluate_simple(&(val,), false)210 } else {210 } else {211 Ok(val)211 Ok(val)212 }212 }213}213}214214215fn array_top1(arr: ArrValue, key_f: Option<FuncVal>, ordering: Ordering) -> Result<Val> {215fn array_top1(arr: ArrValue, key_f: Option<&FuncVal>, ordering: Ordering) -> Result<Val> {216 let mut iter = arr.iter();216 let mut iter = arr.iter();217 let mut min = iter.next().expect("not empty")?;217 let mut min = iter.next().expect("not empty")?;218 let mut min_key = eval_keyf(min.clone(), &key_f)?;218 let mut min_key = eval_keyf(min.clone(), key_f)?;219 for item in iter {219 for item in iter {220 let cur = item?;220 let cur = item?;221 let cur_key = eval_keyf(cur.clone(), &key_f)?;221 let cur_key = eval_keyf(cur.clone(), key_f)?;222 if evaluate_compare_op(&cur_key, &min_key, BinaryOpType::Lt)? == ordering {222 if evaluate_compare_op(&cur_key, &min_key, BinaryOpType::Lt)? == ordering {223 min = cur;223 min = cur;224 min_key = cur_key;224 min_key = cur_key;236 if arr.is_empty() {236 if arr.is_empty() {237 return eval_on_empty(onEmpty);237 return eval_on_empty(onEmpty);238 }238 }239 array_top1(arr, keyF, Ordering::Less)239 array_top1(arr, keyF.as_ref(), Ordering::Less)240}240}241#[builtin]241#[builtin]242pub fn builtin_max_array(242pub fn builtin_max_array(247 if arr.is_empty() {247 if arr.is_empty() {248 return eval_on_empty(onEmpty);248 return eval_on_empty(onEmpty);249 }249 }250 array_top1(arr, keyF, Ordering::Greater)250 array_top1(arr, keyF.as_ref(), Ordering::Greater)251}251}252252crates/jrsonnet-stdlib/src/strings.rsdiffbeforeafterboth535354#[builtin]54#[builtin]55pub fn builtin_equals_ignore_case(str1: String, str2: String) -> bool {55pub fn builtin_equals_ignore_case(str1: String, str2: String) -> bool {56 str1.to_ascii_lowercase() == str2.to_ascii_lowercase()56 str1.eq_ignore_ascii_case(&str2)57}57}585859#[builtin]59#[builtin]crates/jrsonnet-types/src/lib.rsdiffbeforeafterboth133 Self::Sum(v) => write_union(f, false, v.iter())?,133 Self::Sum(v) => write_union(f, false, v.iter())?,134 Self::SumRef(v) => write_union(f, false, v.iter().copied())?,134 Self::SumRef(v) => write_union(f, false, v.iter().copied())?,135 Self::Lazy(lazy) => write!(f, "Lazy<{lazy}>")?,135 Self::Lazy(lazy) => write!(f, "Lazy<{lazy}>")?,136 };136 }137 Ok(())137 Ok(())138 }138 }139}139}tests/tests/common.rsdiffbeforeafterboth57#[builtin]57#[builtin]58fn param_names(fun: FuncVal) -> Vec<String> {58fn param_names(fun: FuncVal) -> Vec<String> {59 fun.params()59 fun.params()60 .into_iter()60 .iter()61 .map(|v| v.name().as_str().unwrap_or("<unnamed>").to_owned())61 .map(|v| v.name().as_str().unwrap_or("<unnamed>").to_owned())62 .collect()62 .collect()63}63}646465#[derive(Trace)]65#[derive(Trace)]66#[allow(dead_code)]66pub struct ContextInitializer;67pub struct ContextInitializer;67impl ContextInitializerT for ContextInitializer {68impl ContextInitializerT for ContextInitializer {68 fn populate(&self, _for_file: Source, builder: &mut ContextBuilder) {69 fn populate(&self, _for_file: Source, builder: &mut ContextBuilder) {tests/tests/cpp_test_suite.rsdiffbeforeafterboth23 // C++ test suite23 // C++ test suite24 std_context.add_ext_str("var1".into(), "test".into());24 std_context.add_ext_str("var1".into(), "test".into());25 std_context25 std_context26 .add_ext_code("var2".into(), "{x:1,y:2}")26 .add_ext_code("var2", "{x:1,y:2}")27 .expect("code is valid");27 .expect("code is valid");282829 // Golang test suite29 // Golang test suite30 std_context30 std_context31 .add_ext_code("codeVar".into(), "3+3")31 .add_ext_code("codeVar", "3+3")32 .expect("code is valid");32 .expect("code is valid");33 std_context.add_ext_str("stringVar".into(), "2 + 2".into());33 std_context.add_ext_str("stringVar".into(), "2 + 2".into());34 std_context34 std_context35 .add_ext_code(35 .add_ext_code(36 "selfRecursiveVar".into(),36 "selfRecursiveVar",37 r#"[42, std.extVar("selfRecursiveVar")[0] + 1]"#,37 r#"[42, std.extVar("selfRecursiveVar")[0] + 1]"#,38 )38 )39 .expect("code is valid");39 .expect("code is valid");40 std_context40 std_context41 .add_ext_code(41 .add_ext_code(42 "mutuallyRecursiveVar1".into(),42 "mutuallyRecursiveVar1",43 r#"[42, std.extVar("mutuallyRecursiveVar2")[0] + 1]"#,43 r#"[42, std.extVar("mutuallyRecursiveVar2")[0] + 1]"#,44 )44 )45 .expect("code is valid");45 .expect("code is valid");46 std_context46 std_context47 .add_ext_code(47 .add_ext_code(48 "mutuallyRecursiveVar2".into(),48 "mutuallyRecursiveVar2",49 r#"[42, std.extVar("mutuallyRecursiveVar1")[0] + 1]"#,49 r#"[42, std.extVar("mutuallyRecursiveVar1")[0] + 1]"#,50 )50 )51 .expect("code is valid");51 .expect("code is valid");203 let root = root_tests.join(root_dir);203 let root = root_tests.join(root_dir);204 let root_override = root_tests.join(format!("{root_dir}_golden_override"));204 let root_override = root_tests.join(format!("{root_dir}_golden_override"));205205206 for entry in fs::read_dir(&root).map_err(|e| io::Error::new(ErrorKind::Other, format!("failed to enumerate cpp_test_suite dir (Note: it needs to be cloned from C++ jsonnet repo for this test): {e}")))? {206 for entry in fs::read_dir(&root).map_err(|e| io::Error::other(format!("failed to enumerate cpp_test_suite dir (Note: it needs to be cloned from C++ jsonnet repo for this test): {e}")))? {207 let entry = entry?;207 let entry = entry?;208 if !entry.path().extension().map_or(false, |e| e == "jsonnet") {208 if entry.path().extension().is_none_or(|e| e != "jsonnet") {209 continue;209 continue;210 }210 }211211212 if entry212 if entry213 .path()213 .path()214 .file_name()214 .file_name()215 .and_then(|v| v.to_str())215 .and_then(|v| v.to_str())216 .map_or(false, |v| SKIPPED.contains(&v))216 .is_some_and(|v| SKIPPED.contains(&v))217 {217 {218 continue;218 continue;219 }219 }227 golden_path2.set_extension("golden");227 golden_path2.set_extension("golden");228228229 let golden_override =229 let golden_override =230 root_override.join(&golden_path.file_name().expect("file has basename"));230 root_override.join(golden_path.file_name().expect("file has basename"));231231232 // .jsonnet.golden for C++ tests232 // .jsonnet.golden for C++ tests233 let mut golden = read_file(&golden_path)?;233 let mut golden = read_file(&golden_path)?;282 }282 }283 }283 }284 }284 }285 };285 }286 }286 }287 }287 }288288tests/tests/golden.rsdiffbeforeafterboth40#[test]40#[test]41fn golden() {41fn golden() {42 glob!("../", "golden/*.jsonnet", |path| {42 glob!("../", "golden/*.jsonnet", |path| {43 let result = run(&path);43 let result = run(path);444445 assert_snapshot!(result)45 assert_snapshot!(result);46 });46 });47}47}4848tests/tests/suite.rsdiffbeforeafterboth32 file.display(),32 file.display(),33 trace_format.format(&e).unwrap()33 trace_format.format(&e).unwrap()34 ),34 ),35 };35 }36}36}373738#[test]38#[test]424243 for entry in fs::read_dir(&root)? {43 for entry in fs::read_dir(&root)? {44 let entry = entry?;44 let entry = entry?;45 if !entry.path().extension().map_or(false, |e| e == "jsonnet") {45 if entry.path().extension().is_some_and(|e| e == "jsonnet") {46 continue;46 run(&entry.path());47 }47 }4849 run(&entry.path());50 }48 }514952 Ok(())50 Ok(())