difftreelog
style switch clippy to pedantic
in: master
25 files changed
crates/jrsonnet-evaluator/src/builtin/format.rsdiffbeforeafterboth86 }86 }87}87}888889#[allow(clippy::struct_excessive_bools)]89#[derive(Default, Debug)]90#[derive(Default, Debug)]90pub struct CFlags {91pub struct CFlags {91 pub alt: bool,92 pub alt: bool,270 return Ok(out);271 return Ok(out);271 }272 }272 str = &str[offset + 1..];273 str = &str[offset + 1..];273 let (code, nstr) = parse_code(str)?;274 let code;274 str = nstr;275 (code, str) = parse_code(str)?;275 bytes = str.as_bytes();276 bytes = str.as_bytes();276 offset = 0;277 offset = 0;277278278 out.push(Element::Code(code))279 out.push(Element::Code(code));279 }280 }280}281}281282313 .saturating_sub(prefix.len() + digits.len());314 .saturating_sub(prefix.len() + digits.len());314315315 if neg {316 if neg {316 out.push('-')317 out.push('-');317 } else if sign {318 } else if sign {318 out.push('+');319 out.push('+');319 } else if blank {320 } else if blank {340 blank: bool,341 blank: bool,341 sign: bool,342 sign: bool,342) {343) {343 render_integer(out, iv, padding, precision, blank, sign, 10, "", false)344 render_integer(out, iv, padding, precision, blank, sign, 10, "", false);344}345}345pub fn render_octal(346pub fn render_octal(346 out: &mut String,347 out: &mut String,361 8,362 8,362 if alt && iv != 0 { "0" } else { "" },363 if alt && iv != 0 { "0" } else { "" },363 false,364 false,364 )365 );365}366}367368#[allow(clippy::fn_params_excessive_bools)]366pub fn render_hexadecimal(369pub fn render_hexadecimal(367 out: &mut String,370 out: &mut String,368 iv: i64,371 iv: i64,387 (false, _) => "",390 (false, _) => "",388 },391 },389 caps,392 caps,390 )393 );391}394}392395396#[allow(clippy::fn_params_excessive_bools)]393pub fn render_float(397pub fn render_float(394 out: &mut String,398 out: &mut String,395 n: f64,399 n: f64,431 }435 }432}436}433437438#[allow(clippy::fn_params_excessive_bools)]434pub fn render_float_sci(439pub fn render_float_sci(435 out: &mut String,440 out: &mut String,436 n: f64,441 n: f64,461 out.push_str(&exponent_str);466 out.push_str(&exponent_str);462}467}463468469#[allow(clippy::too_many_lines)]464pub fn format_code(470pub fn format_code(465 s: State,471 s: State,466 out: &mut String,472 out: &mut String,crates/jrsonnet-evaluator/src/builtin/manifest.rsdiffbeforeafterboth158 '\r' => buf.push_str("\\r"),158 '\r' => buf.push_str("\\r"),159 '\t' => buf.push_str("\\t"),159 '\t' => buf.push_str("\\t"),160 c if c < 32 as char || (c >= 127 as char && c <= 159 as char) => {160 c if c < 32 as char || (c >= 127 as char && c <= 159 as char) => {161 write!(buf, "\\u{:04x}", c as u32).unwrap()161 write!(buf, "\\u{:04x}", c as u32).unwrap();162 }162 }163 c => buf.push(c),163 c => buf.push(c),164 }164 }194 pub preserve_order: bool,194 pub preserve_order: bool,195}195}196196197/// From https://github.com/chyh1990/yaml-rust/blob/da52a68615f2ecdd6b7e4567019f280c433c1521/src/emitter.rs#L289197/// From <https://github.com/chyh1990/yaml-rust/blob/da52a68615f2ecdd6b7e4567019f280c433c1521/src/emitter.rs#L289>198/// With added date check198/// With added date check199fn yaml_needs_quotes(string: &str) -> bool {199fn yaml_needs_quotes(string: &str) -> bool {200 fn need_quotes_spaces(string: &str) -> bool {200 fn need_quotes_spaces(string: &str) -> bool {228 Ok(out)228 Ok(out)229}229}230231#[allow(clippy::too_many_lines)]230fn manifest_yaml_ex_buf(232fn manifest_yaml_ex_buf(231 s: State,233 s: State,232 val: &Val,234 val: &Val,238 match val {240 match val {239 Val::Bool(v) => {241 Val::Bool(v) => {240 if *v {242 if *v {241 buf.push_str("true")243 buf.push_str("true");242 } else {244 } else {243 buf.push_str("false")245 buf.push_str("false");244 }246 }245 }247 }246 Val::Null => buf.push_str("null"),248 Val::Null => buf.push_str("null"),crates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth1// All builtins should return results2#![allow(clippy::unnecessary_wraps)]31use std::collections::HashMap;4use std::collections::HashMap;25173fn builtin_make_array(s: State, sz: usize, func: FuncVal) -> Result<VecVal> {176fn builtin_make_array(s: State, sz: usize, func: FuncVal) -> Result<VecVal> {174 let mut out = Vec::with_capacity(sz);177 let mut out = Vec::with_capacity(sz);175 for i in 0..sz {178 for i in 0..sz {176 out.push(func.evaluate_simple(s.clone(), &[i as f64].as_slice())?)179 out.push(func.evaluate_simple(s.clone(), &[i as f64].as_slice())?);177 }180 }178 Ok(VecVal(Cc::new(out)))181 Ok(VecVal(Cc::new(out)))179}182}420 match func.evaluate_simple(s.clone(), &[Any(el)].as_slice())? {423 match func.evaluate_simple(s.clone(), &[Any(el)].as_slice())? {421 Val::Arr(o) => {424 Val::Arr(o) => {422 for oe in o.iter(s.clone()) {425 for oe in o.iter(s.clone()) {423 out.push(oe?)426 out.push(oe?);424 }427 }425 }428 }426 _ => throw!(RuntimeError(429 _ => throw!(RuntimeError(707#[jrsonnet_macros::builtin]710#[jrsonnet_macros::builtin]708fn builtin_count(s: State, arr: Vec<Any>, v: Any) -> Result<usize> {711fn builtin_count(s: State, arr: Vec<Any>, v: Any) -> Result<usize> {709 let mut count = 0;712 let mut count = 0;710 for item in arr.iter() {713 for item in &arr {711 if equals(s.clone(), &item.0, &v.0)? {714 if equals(s.clone(), &item.0, &v.0)? {712 count += 1;715 count += 1;713 }716 }crates/jrsonnet-evaluator/src/builtin/sort.rsdiffbeforeafterboth53 match (i, sort_type) {53 match (i, sort_type) {54 (Val::Str(_), SortKeyType::Unknown) => sort_type = SortKeyType::String,54 (Val::Str(_), SortKeyType::Unknown) => sort_type = SortKeyType::String,55 (Val::Num(_), SortKeyType::Unknown) => sort_type = SortKeyType::Number,55 (Val::Num(_), SortKeyType::Unknown) => sort_type = SortKeyType::Number,56 (Val::Str(_), SortKeyType::String) => {}56 (Val::Str(_), SortKeyType::String) | (Val::Num(_), SortKeyType::Number) => {}57 (Val::Str(_), _) => throw!(SortError::SortElementsShouldHaveEqualType),58 (Val::Num(_), SortKeyType::Number) => {}59 (Val::Num(_), _) => throw!(SortError::SortElementsShouldHaveEqualType),57 (Val::Str(_) | Val::Num(_), _) => {58 throw!(SortError::SortElementsShouldHaveEqualType)59 }60 _ => throw!(SortError::SortKeyShouldBeStringOrNumber),60 _ => throw!(SortError::SortKeyShouldBeStringOrNumber),61 }61 }62 }62 }91 Ok(Cc::new(vk.into_iter().map(|v| v.0).collect()))91 Ok(Cc::new(vk.into_iter().map(|v| v.0).collect()))92 } else {92 } else {93 // Fast path, identity key getter93 // Fast path, identity key getter94 let mut mvalues = (*values).clone();94 let mut values = (*values).clone();95 let sort_type = get_sort_type(&mut mvalues, |k| k)?;95 let sort_type = get_sort_type(&mut values, |k| k)?;96 match sort_type {96 match sort_type {97 SortKeyType::Number => mvalues.sort_unstable_by_key(|v| match v {97 SortKeyType::Number => values.sort_unstable_by_key(|v| match v {98 Val::Num(n) => NonNaNf64(*n),98 Val::Num(n) => NonNaNf64(*n),99 _ => unreachable!(),99 _ => unreachable!(),100 }),100 }),101 SortKeyType::String => mvalues.sort_unstable_by_key(|v| match v {101 SortKeyType::String => values.sort_unstable_by_key(|v| match v {102 Val::Str(s) => s.clone(),102 Val::Str(s) => s.clone(),103 _ => unreachable!(),103 _ => unreachable!(),104 }),104 }),105 SortKeyType::Unknown => unreachable!(),105 SortKeyType::Unknown => unreachable!(),106 };106 };107 Ok(Cc::new(mvalues))107 Ok(Cc::new(values))108 }108 }109}109}110110crates/jrsonnet-evaluator/src/builtin/stdlib.rsdiffbeforeafterboth24}24}252526pub fn get_parsed_stdlib() -> LocExpr {26pub fn get_parsed_stdlib() -> LocExpr {27 PARSED_STDLIB.with(|t| t.clone())27 PARSED_STDLIB.with(Clone::clone)28}28}2929crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth79 pub fn contains_binding(&self, name: IStr) -> bool {79 pub fn contains_binding(&self, name: IStr) -> bool {80 self.0.bindings.contains_key(&name)80 self.0.bindings.contains_key(&name)81 }81 }82 #[must_use]82 pub fn into_future(self, ctx: FutureWrapper<Self>) -> Self {83 pub fn into_future(self, ctx: FutureWrapper<Self>) -> Self {83 {84 {84 ctx.0.borrow_mut().replace(self);85 ctx.0.borrow_mut().replace(self);85 }86 }86 ctx.unwrap()87 ctx.unwrap()87 }88 }888990 #[must_use]89 pub fn with_var(self, name: IStr, value: Val) -> Self {91 pub fn with_var(self, name: IStr, value: Val) -> Self {90 let mut new_bindings = GcHashMap::with_capacity(1);92 let mut new_bindings = GcHashMap::with_capacity(1);91 new_bindings.insert(name, LazyVal::new_resolved(value));93 new_bindings.insert(name, LazyVal::new_resolved(value));92 self.extend(new_bindings, None, None, None)94 self.extend(new_bindings, None, None, None)93 }95 }949697 #[must_use]95 pub fn with_this_super(self, new_this: ObjValue, new_super_obj: Option<ObjValue>) -> Self {98 pub fn with_this_super(self, new_this: ObjValue, new_super_obj: Option<ObjValue>) -> Self {96 self.extend(GcHashMap::new(), None, Some(new_this), new_super_obj)99 self.extend(GcHashMap::new(), None, Some(new_this), new_super_obj)97 }100 }98101102 #[must_use]99 pub fn extend(103 pub fn extend(100 self,104 self,101 new_bindings: GcHashMap<IStr, LazyVal>,105 new_bindings: GcHashMap<IStr, LazyVal>,119 bindings,123 bindings,120 }))124 }))121 }125 }126 #[must_use]122 pub fn extend_bound(self, new_bindings: GcHashMap<IStr, LazyVal>) -> Self {127 pub fn extend_bound(self, new_bindings: GcHashMap<IStr, LazyVal>) -> Self {123 let new_this = self.0.this.clone();128 let new_this = self.0.this.clone();124 let new_super_obj = self.0.super_obj.clone();129 let new_super_obj = self.0.super_obj.clone();135 let this = new_this.or_else(|| self.0.this.clone());140 let this = new_this.or_else(|| self.0.this.clone());136 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());141 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());137 let mut new = GcHashMap::with_capacity(new_bindings.len());142 let mut new = GcHashMap::with_capacity(new_bindings.len());138 for (k, v) in new_bindings.0.into_iter() {143 for (k, v) in new_bindings.0 {139 new.insert(k, v.evaluate(s.clone(), this.clone(), super_obj.clone())?);144 new.insert(k, v.evaluate(s.clone(), this.clone(), super_obj.clone())?);140 }145 }141 Ok(self.extend(new, new_dollar, this, super_obj))146 Ok(self.extend(new, new_dollar, this, super_obj))crates/jrsonnet-evaluator/src/dynamic.rsdiffbeforeafterboth8 pub fn new() -> Self {8 pub fn new() -> Self {9 Self(Cc::new(RefCell::new(None)))9 Self(Cc::new(RefCell::new(None)))10 }10 }11 /// # Panics12 /// If wrapper is filled already11 pub fn fill(self, value: T) {13 pub fn fill(self, value: T) {12 assert!(self.0.borrow().is_none(), "wrapper is filled already");14 assert!(self.0.borrow().is_none(), "wrapper is filled already");13 self.0.borrow_mut().replace(value);15 self.0.borrow_mut().replace(value);14 }16 }15}17}16impl<T: Clone + Trace + 'static> FutureWrapper<T> {18impl<T: Clone + Trace + 'static> FutureWrapper<T> {19 /// # Panics20 /// If wrapper is not yet filled17 pub fn unwrap(&self) -> T {21 pub fn unwrap(&self) -> T {18 self.0.borrow().as_ref().cloned().unwrap()22 self.0.borrow().as_ref().cloned().unwrap()19 }23 }crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth96 #[error(96 #[error(97 "syntax error: expected {}, got {:?}",97 "syntax error: expected {}, got {:?}",98 .error.expected,98 .error.expected,99 .source_code.chars().nth(error.location.offset).map(|c| c.to_string()).unwrap_or_else(|| "EOF".into())99 .source_code.chars().nth(error.location.offset)100 .map_or_else(|| "EOF".into(), |c| c.to_string())100 )]101 )]101 ImportSyntaxError {102 ImportSyntaxError {102 #[skip_trace]103 #[skip_trace]190impl Debug for LocError {191impl Debug for LocError {191 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {192 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {192 writeln!(f, "{}", self.0 .0)?;193 writeln!(f, "{}", self.0 .0)?;193 for el in self.0 .1 .0.iter() {194 for el in &self.0 .1 .0 {194 writeln!(f, "\t{:?}", el)?;195 writeln!(f, "\t{:?}", el)?;195 }196 }196 Ok(())197 Ok(())crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth23pub fn evaluate_binding_in_future(b: &BindSpec, fctx: FutureWrapper<Context>) -> LazyVal {23pub fn evaluate_binding_in_future(b: &BindSpec, fctx: FutureWrapper<Context>) -> LazyVal {24 let b = b.clone();24 let b = b.clone();25 if let Some(params) = &b.params {25 if let Some(params) = &b.params {26 let params = params.clone();2728 #[derive(Trace)]26 #[derive(Trace)]29 struct LazyMethodBinding {27 struct LazyMethodBinding {43 }41 }44 }42 }4344 let params = params.clone();454546 LazyVal::new(TraceBox(Box::new(LazyMethodBinding {46 LazyVal::new(TraceBox(Box::new(LazyMethodBinding {47 fctx,47 fctx,69 }69 }70}70}717172#[allow(clippy::too_many_lines)]72pub fn evaluate_binding(b: &BindSpec, cctx: ContextCreator) -> (IStr, LazyBinding) {73pub fn evaluate_binding(b: &BindSpec, cctx: ContextCreator) -> (IStr, LazyBinding) {73 let b = b.clone();74 let b = b.clone();74 if let Some(params) = &b.params {75 if let Some(params) = &b.params {75 let params = params.clone();7677 #[derive(Trace)]76 #[derive(Trace)]78 struct BindableMethodLazyVal {77 struct BindableMethodLazyVal {121 }120 }122 }121 }122123 let params = params.clone();123124124 (125 (125 b.name.clone(),126 b.name.clone(),227 None => callback(ctx)?,228 None => callback(ctx)?,228 Some(CompSpec::IfSpec(IfSpecData(cond))) => {229 Some(CompSpec::IfSpec(IfSpecData(cond))) => {229 if bool::from_untyped(evaluate(s.clone(), ctx.clone(), cond)?, s.clone())? {230 if bool::from_untyped(evaluate(s.clone(), ctx.clone(), cond)?, s.clone())? {230 evaluate_comp(s, ctx, &specs[1..], callback)?231 evaluate_comp(s, ctx, &specs[1..], callback)?;231 }232 }232 }233 }233 Some(CompSpec::ForSpec(ForSpecData(var, expr))) => {234 Some(CompSpec::ForSpec(ForSpecData(var, expr))) => {239 ctx.clone().with_var(var.clone(), item?.clone()),240 ctx.clone().with_var(var.clone(), item?.clone()),240 &specs[1..],241 &specs[1..],241 callback,242 callback,242 )?243 )?;243 }244 }244 }245 }245 _ => throw!(InComprehensionCanOnlyIterateOverArray),246 _ => throw!(InComprehensionCanOnlyIterateOverArray),249 Ok(())250 Ok(())250}251}251252253#[allow(clippy::too_many_lines)]252pub fn evaluate_member_list_object(s: State, ctx: Context, members: &[Member]) -> Result<ObjValue> {254pub fn evaluate_member_list_object(s: State, ctx: Context, members: &[Member]) -> Result<ObjValue> {253 let new_bindings = FutureWrapper::new();255 let new_bindings = FutureWrapper::new();254 let future_this = FutureWrapper::new();256 let future_this = FutureWrapper::new();278 visibility,280 visibility,279 value,281 value,280 }) => {282 }) => {281 let name = evaluate_field_name(s.clone(), ctx.clone(), name)?;282 if name.is_none() {283 continue;284 }285 let name = name.unwrap();286287 #[derive(Trace)]283 #[derive(Trace)]288 struct ObjMemberBinding {284 struct ObjMemberBinding {306 }302 }307 }303 }304305 let name = evaluate_field_name(s.clone(), ctx.clone(), name)?;306 let name = if let Some(name) = name {307 name308 } else {309 continue;310 };311308 builder312 builder309 .member(name.clone())313 .member(name.clone())325 value,329 value,326 ..330 ..327 }) => {331 }) => {328 let name = evaluate_field_name(s.clone(), ctx.clone(), name)?;329 if name.is_none() {330 continue;331 }332 let name = name.unwrap();333 #[derive(Trace)]332 #[derive(Trace)]334 struct ObjMemberBinding {333 struct ObjMemberBinding {335 cctx: ContextCreator,334 cctx: ContextCreator,353 }352 }354 }353 }354355 let name = if let Some(name) = evaluate_field_name(s.clone(), ctx.clone(), name)? {356 name357 } else {358 continue;359 };360355 builder361 builder356 .member(name.clone())362 .member(name.clone())505 throw!(AssertionFailed(511 throw!(AssertionFailed(506 evaluate(s.clone(), ctx, msg)?.to_string(s.clone())?512 evaluate(s.clone(), ctx, msg)?.to_string(s.clone())?507 ));513 ));508 } else {514 }509 throw!(AssertionFailed(Val::Null.to_string(s.clone())?));515 throw!(AssertionFailed(Val::Null.to_string(s.clone())?));510 }511 },516 },512 )?517 )?;513 }518 }514 Ok(())519 Ok(())515}520}516521517pub fn evaluate_named(s: State, ctx: Context, lexpr: &LocExpr, name: IStr) -> Result<Val> {522pub fn evaluate_named(s: State, ctx: Context, expr: &LocExpr, name: IStr) -> Result<Val> {518 use Expr::*;523 use Expr::*;519 let LocExpr(expr, _loc) = lexpr;524 let LocExpr(raw_expr, _loc) = expr;520 Ok(match &**expr {525 Ok(match &**raw_expr {521 Function(params, body) => evaluate_method(ctx, name, params.clone(), body.clone()),526 Function(params, body) => evaluate_method(ctx, name, params.clone(), body.clone()),522 _ => evaluate(s, ctx, lexpr)?,527 _ => evaluate(s, ctx, expr)?,523 })528 })524}529}525530531#[allow(clippy::too_many_lines)]526pub fn evaluate(s: State, ctx: Context, expr: &LocExpr) -> Result<Val> {532pub fn evaluate(s: State, ctx: Context, expr: &LocExpr) -> Result<Val> {527 use Expr::*;533 use Expr::*;528 let LocExpr(expr, loc) = expr;534 let LocExpr(expr, loc) = expr;535 ctx.super_obj()541 ctx.super_obj().clone().ok_or(NoSuperFound)?.with_this(536 .clone()537 .ok_or(NoSuperFound)?538 .with_this(ctx.this().clone().unwrap()),542 ctx.this()543 .clone()544 .expect("if super exists - then this should to"),545 ),539 ),546 ),540 Literal(LiteralType::Dollar) => {547 Literal(LiteralType::Dollar) => {699 }706 }700 }707 }701 Slice(value, desc) => {708 Slice(value, desc) => {702 let indexable = evaluate(s.clone(), ctx.clone(), value)?;703 let loc = CallLocation::new(loc);704705 fn parse_idx<T: Typed>(709 fn parse_idx<T: Typed>(706 loc: CallLocation,710 loc: CallLocation,720 }724 }721 }725 }726727 let indexable = evaluate(s.clone(), ctx.clone(), value)?;728 let loc = CallLocation::new(loc);722729723 let start = parse_idx(loc, s.clone(), &ctx, &desc.start, "start")?;730 let start = parse_idx(loc, s.clone(), &ctx, &desc.start, "start")?;724 let end = parse_idx(loc, s.clone(), &ctx, &desc.end, "end")?;731 let end = parse_idx(loc, s.clone(), &ctx, &desc.end, "end")?;crates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth1use std::cmp::Ordering;21use jrsonnet_parser::{BinaryOpType, LocExpr, UnaryOpType};3use jrsonnet_parser::{BinaryOpType, LocExpr, UnaryOpType};2411 Ok(match (op, b) {13 Ok(match (op, b) {12 (Not, Bool(v)) => Bool(!v),14 (Not, Bool(v)) => Bool(!v),13 (Minus, Num(n)) => Num(-*n),15 (Minus, Num(n)) => Num(-*n),14 (BitNot, Num(n)) => Num(!(*n as i32) as f64),16 (BitNot, Num(n)) => Num(f64::from(!(*n as i32))),15 (op, o) => throw!(UnaryOperatorDoesNotOperateOnType(op, o.value_type())),17 (op, o) => throw!(UnaryOperatorDoesNotOperateOnType(op, o.value_type())),16 })18 })17}19}22 (Str(v1), Str(v2)) => Str(((**v1).to_owned() + v2).into()),24 (Str(v1), Str(v2)) => Str(((**v1).to_owned() + v2).into()),232524 // Can't use generic json serialization way, because it depends on number to string concatenation (std.jsonnet:890)26 // Can't use generic json serialization way, because it depends on number to string concatenation (std.jsonnet:890)25 (Num(n), Str(o)) => Str(format!("{}{}", n, o).into()),27 (Num(a), Str(b)) => Str(format!("{a}{b}").into()),26 (Str(o), Num(n)) => Str(format!("{}{}", o, n).into()),28 (Str(a), Num(b)) => Str(format!("{a}{b}").into()),272928 (Str(a), o) => Str(format!("{}{}", a, o.clone().to_string(s)?).into()),30 (Str(a), o) => Str(format!("{}{}", a, o.clone().to_string(s)?).into()),29 (o, Str(a)) => Str(format!("{}{}", o.clone().to_string(s)?, a).into()),31 (o, Str(a)) => Str(format!("{}{}", o.clone().to_string(s)?, a).into()),47pub fn evaluate_mod_op(s: State, a: &Val, b: &Val) -> Result<Val> {49pub fn evaluate_mod_op(s: State, a: &Val, b: &Val) -> Result<Val> {48 use Val::*;50 use Val::*;49 match (a, b) {51 match (a, b) {50 (Num(a), Num(b)) => Ok(Num(a % b)),52 (Num(a), Num(b)) => {53 if *b == 0.0 {54 throw!(DivisionByZero)55 }56 Ok(Num(a % b))57 }51 (Str(str), vals) => {58 (Str(str), vals) => {52 String::into_untyped(std_format(s.clone(), str.clone(), vals.clone())?, s)59 String::into_untyped(std_format(s.clone(), str.clone(), vals.clone())?, s)53 }60 }75 })82 })76}83}8485pub fn evaluate_compare_op(s: State, a: &Val, op: BinaryOpType, b: &Val) -> Result<Ordering> {86 use Val::*;87 Ok(match (a, b) {88 (Str(a), Str(b)) => a.cmp(b),89 (Num(a), Num(b)) => a.partial_cmp(b).expect("jsonnet numbers are non NaN"),90 (Arr(a), Arr(b)) => {91 let ai = a.iter(s.clone());92 let bi = b.iter(s.clone());9394 for (a, b) in ai.zip(bi) {95 let ord = evaluate_compare_op(s.clone(), &a?, op, &b?)?;96 if !ord.is_eq() {97 return Ok(ord);98 }99 }100101 a.len().cmp(&b.len())102 }103 (_, _) => throw!(BinaryOperatorDoesNotOperateOnValues(104 op,105 a.value_type(),106 b.value_type()107 )),108 })109}7711078pub fn evaluate_binary_op_normal(s: State, a: &Val, op: BinaryOpType, b: &Val) -> Result<Val> {111pub fn evaluate_binary_op_normal(s: State, a: &Val, op: BinaryOpType, b: &Val) -> Result<Val> {79 use BinaryOpType::*;112 use BinaryOpType::*;84 (a, Eq, b) => Bool(equals(s, a, b)?),117 (a, Eq, b) => Bool(equals(s, a, b)?),85 (a, Neq, b) => Bool(!equals(s, a, b)?),118 (a, Neq, b) => Bool(!equals(s, a, b)?),119120 (a, Lt, b) => Bool(evaluate_compare_op(s, a, Lt, b)?.is_lt()),121 (a, Gt, b) => Bool(evaluate_compare_op(s, a, Gt, b)?.is_gt()),122 (a, Lte, b) => Bool(evaluate_compare_op(s, a, Lte, b)?.is_le()),123 (a, Gte, b) => Bool(evaluate_compare_op(s, a, Gte, b)?.is_ge()),8612487 (Str(a), In, Obj(obj)) => Bool(obj.has_field_ex(a.clone(), true)),125 (Str(a), In, Obj(obj)) => Bool(obj.has_field_ex(a.clone(), true)),88 (a, Mod, b) => evaluate_mod_op(s, a, b)?,126 (a, Mod, b) => evaluate_mod_op(s, a, b)?,93 (Bool(a), And, Bool(b)) => Bool(*a && *b),131 (Bool(a), And, Bool(b)) => Bool(*a && *b),94 (Bool(a), Or, Bool(b)) => Bool(*a || *b),132 (Bool(a), Or, Bool(b)) => Bool(*a || *b),9596 // Str X Str97 (Str(v1), Lt, Str(v2)) => Bool(v1 < v2),98 (Str(v1), Gt, Str(v2)) => Bool(v1 > v2),99 (Str(v1), Lte, Str(v2)) => Bool(v1 <= v2),100 (Str(v1), Gte, Str(v2)) => Bool(v1 >= v2),101133102 // Num X Num134 // Num X Num103 (Num(v1), Mul, Num(v2)) => Val::new_checked_num(v1 * v2)?,135 (Num(v1), Mul, Num(v2)) => Val::new_checked_num(v1 * v2)?,104 (Num(v1), Div, Num(v2)) => {136 (Num(v1), Div, Num(v2)) => {105 if *v2 <= f64::EPSILON {137 if *v2 == 0.0 {106 throw!(DivisionByZero)138 throw!(DivisionByZero)107 }139 }108 Val::new_checked_num(v1 / v2)?140 Val::new_checked_num(v1 / v2)?109 }141 }110142111 (Num(v1), Sub, Num(v2)) => Val::new_checked_num(v1 - v2)?,143 (Num(v1), Sub, Num(v2)) => Val::new_checked_num(v1 - v2)?,112113 (Num(v1), Lt, Num(v2)) => Bool(v1 < v2),114 (Num(v1), Gt, Num(v2)) => Bool(v1 > v2),115 (Num(v1), Lte, Num(v2)) => Bool(v1 <= v2),116 (Num(v1), Gte, Num(v2)) => Bool(v1 >= v2),117144118 (Num(v1), BitAnd, Num(v2)) => Num(((*v1 as i32) & (*v2 as i32)) as f64),145 (Num(v1), BitAnd, Num(v2)) => Num(f64::from((*v1 as i32) & (*v2 as i32))),119 (Num(v1), BitOr, Num(v2)) => Num(((*v1 as i32) | (*v2 as i32)) as f64),146 (Num(v1), BitOr, Num(v2)) => Num(f64::from((*v1 as i32) | (*v2 as i32))),120 (Num(v1), BitXor, Num(v2)) => Num(((*v1 as i32) ^ (*v2 as i32)) as f64),147 (Num(v1), BitXor, Num(v2)) => Num(f64::from((*v1 as i32) ^ (*v2 as i32))),121 (Num(v1), Lhs, Num(v2)) => {148 (Num(v1), Lhs, Num(v2)) => {122 if *v2 < 0.0 {149 if *v2 < 0.0 {123 throw!(RuntimeError("shift by negative exponent".into()))150 throw!(RuntimeError("shift by negative exponent".into()))124 }151 }125 Num(((*v1 as i32) << (*v2 as i32)) as f64)152 Num(f64::from((*v1 as i32) << (*v2 as i32)))126 }153 }127 (Num(v1), Rhs, Num(v2)) => {154 (Num(v1), Rhs, Num(v2)) => {128 if *v2 < 0.0 {155 if *v2 < 0.0 {129 throw!(RuntimeError("shift by negative exponent".into()))156 throw!(RuntimeError("shift by negative exponent".into()))130 }157 }131 Num(((*v1 as i32) >> (*v2 as i32)) as f64)158 Num(f64::from((*v1 as i32) >> (*v2 as i32)))132 }159 }133160134 _ => throw!(BinaryOperatorDoesNotOperateOnValues(161 _ => throw!(BinaryOperatorDoesNotOperateOnValues(crates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth145 tailstrict: bool,145 tailstrict: bool,146 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,146 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,147 ) -> Result<()> {147 ) -> Result<()> {148 for (name, arg) in self.named.iter() {148 for (name, arg) in &self.named {149 handler(149 handler(150 name,150 name,151 if tailstrict {151 if tailstrict {162 }162 }163163164 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {164 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {165 for (name, _) in self.named.iter() {165 for (name, _) in &self.named {166 handler(name)166 handler(name);167 }167 }168 }168 }169}169}231 }231 }232}232}233233234impl<A: ArgLike> ArgsLike for HashMap<IStr, A> {234impl<A: ArgLike, S> ArgsLike for HashMap<IStr, A, S> {235 fn unnamed_len(&self) -> usize {235 fn unnamed_len(&self) -> usize {236 0236 0237 }237 }325 }325 }326326327 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {327 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {328 (*self).named_names(handler)328 (*self).named_names(handler);329 }329 }330}330}331331381 if passed_args.contains_key(¶m.0.clone()) {381 if passed_args.contains_key(¶m.0.clone()) {382 continue;382 continue;383 }383 }384 LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {385 ctx: fctx.clone(),386 name: param.0.clone(),387 value: param.1.clone().unwrap(),388 })));389384390 defaults.insert(385 defaults.insert(391 param.0.clone(),386 param.0.clone(),392 LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {387 LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {393 ctx: fctx.clone(),388 ctx: fctx.clone(),394 name: param.0.clone(),389 name: param.0.clone(),395 value: param.1.clone().unwrap(),390 value: param.1.clone().expect("default exists"),396 }))),391 }))),397 );392 );398 filled_args += 1;393 filled_args += 1;447 // const INST: &'static Self;442 // const INST: &'static Self;448}443}449444450/// You shouldn't probally use this function, use jrsonnet_macros::builtin instead445/// You shouldn't probally use this function, use `jrsonnet_macros::builtin` instead451///446///452/// ## Parameters447/// ## Parameters453/// * `ctx`: used for passed argument expressions' execution and for body execution (if `body_ctx` is not set)448/// * `ctx`: used for passed argument expressions' execution and for body execution (if `body_ctx` is not set)518/// Creates Context, which has all argument default values applied513/// Creates Context, which has all argument default values applied519/// and with unbound values causing error to be returned514/// and with unbound values causing error to be returned520pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Context {515pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Context {521 let fctx = Context::new_future();522523 let mut bindings = GcHashMap::new();524525 #[derive(Trace)]516 #[derive(Trace)]526 struct DependsOnUnbound(IStr);517 struct DependsOnUnbound(IStr);530 }521 }531 }522 }523524 let fctx = Context::new_future();525526 let mut bindings = GcHashMap::new();532527533 for param in params.iter() {528 for param in params.iter() {534 if let Some(v) = ¶m.1 {529 if let Some(v) = ¶m.1 {crates/jrsonnet-evaluator/src/gc.rsdiffbeforeafterboth1/// Macros to help deal with Gc1/// Macros to help deal with Gc2use std::{2use std::{3 borrow::{Borrow, BorrowMut},3 borrow::{Borrow, BorrowMut},4 collections::{HashMap, HashSet},4 hash::BuildHasherDefault,5 hash::BuildHasherDefault,5 ops::{Deref, DerefMut},6 ops::{Deref, DerefMut},6};7};141515impl<T: ?Sized + Trace> Trace for TraceBox<T> {16impl<T: ?Sized + Trace> Trace for TraceBox<T> {16 fn trace(&self, tracer: &mut Tracer) {17 fn trace(&self, tracer: &mut Tracer) {17 self.0.trace(tracer)18 self.0.trace(tracer);18 }19 }192020 fn is_type_tracked() -> bool {21 fn is_type_tracked() -> bool {70pub struct GcHashSet<V>(pub FxHashSet<V>);71pub struct GcHashSet<V>(pub FxHashSet<V>);71impl<V> GcHashSet<V> {72impl<V> GcHashSet<V> {72 pub fn new() -> Self {73 pub fn new() -> Self {73 Self(Default::default())74 Self(HashSet::default())74 }75 }75 pub fn with_capacity(capacity: usize) -> Self {76 pub fn with_capacity(capacity: usize) -> Self {76 Self(FxHashSet::with_capacity_and_hasher(77 Self(FxHashSet::with_capacity_and_hasher(111pub struct GcHashMap<K, V>(pub FxHashMap<K, V>);112pub struct GcHashMap<K, V>(pub FxHashMap<K, V>);112impl<K, V> GcHashMap<K, V> {113impl<K, V> GcHashMap<K, V> {113 pub fn new() -> Self {114 pub fn new() -> Self {114 Self(Default::default())115 Self(HashMap::default())115 }116 }116 pub fn with_capacity(capacity: usize) -> Self {117 pub fn with_capacity(capacity: usize) -> Self {117 Self(FxHashMap::with_capacity_and_hasher(118 Self(FxHashMap::with_capacity_and_hasher(crates/jrsonnet-evaluator/src/import.rsdiffbeforeafterboth79 if direct.exists() {79 if direct.exists() {80 Ok(direct.into())80 Ok(direct.into())81 } else {81 } else {82 for library_path in self.library_paths.iter() {82 for library_path in &self.library_paths {83 let mut cloned = library_path.clone();83 let mut cloned = library_path.clone();84 cloned.push(path);84 cloned.push(path);85 if cloned.exists() {85 if cloned.exists() {crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth1#![warn(clippy::all, clippy::nursery)]1#![warn(clippy::all, clippy::nursery, clippy::pedantic)]2#![allow(2#![allow(3 macro_expanded_macro_exports_accessed_by_absolute_paths,3 macro_expanded_macro_exports_accessed_by_absolute_paths,4 clippy::ptr_arg4 clippy::ptr_arg,5 // Too verbose6 clippy::must_use_candidate,7 // A lot of functions pass around errors thrown by code8 clippy::missing_errors_doc,9 // A lot of pointers have interior Rc10 clippy::needless_pass_by_value,11 // Its fine12 clippy::wildcard_imports,13 clippy::enum_glob_use,14 clippy::module_name_repetitions,15 // TODO: fix individual issues, however this works as intended almost everywhere16 clippy::cast_precision_loss,17 clippy::cast_possible_wrap,18 clippy::cast_possible_truncation,19 clippy::cast_sign_loss,5)]20)]6217// For jrsonnet-macros22// For jrsonnet-macros105 Self {120 Self {106 max_stack: 200,121 max_stack: 200,107 max_trace: 20,122 max_trace: 20,108 globals: Default::default(),123 globals: HashMap::default(),109 ext_vars: Default::default(),124 ext_vars: HashMap::default(),110 ext_natives: Default::default(),125 ext_natives: HashMap::default(),111 tla_vars: Default::default(),126 tla_vars: HashMap::default(),112 import_resolver: Box::new(DummyImportResolver),127 import_resolver: Box::new(DummyImportResolver),113 manifest_format: ManifestFormat::Json {128 manifest_format: ManifestFormat::Json {114 padding: 4,129 padding: 4,161 if self.0.is_empty() {176 if self.0.is_empty() {162 return result;177 return result;163 }178 }164 for item in self.0.iter() {179 for item in &self.0 {165 if item.loc.belongs_to(loc) {180 if item.loc.belongs_to(loc) {166 let mut collected = item.collected.borrow_mut();181 let mut collected = item.collected.borrow_mut();167 let (depth, vals) = collected.entry(stack_generation).or_default();182 let (depth, vals) = collected.entry(stack_generation).or_default();198 )213 )199 .map_err(|error| ImportSyntaxError {214 .map_err(|error| ImportSyntaxError {200 error: Box::new(error),215 error: Box::new(error),201 path: path.to_owned(),216 path: path.clone(),202 source_code: source_code.clone(),217 source_code: source_code.clone(),203 })?;218 })?;204 self.add_parsed_file(path, source_code, parsed.clone())?;219 self.add_parsed_file(path, source_code, parsed.clone())?;210 self.data_mut()225 self.data_mut()211 .files226 .files212 .get_mut(name)227 .get_mut(name)213 .unwrap()228 .expect("file not found")214 .evaluated229 .evaluated215 .take();230 .take();216 }231 }246 line: usize,261 line: usize,247 column: usize,262 column: usize,248 ) -> Option<usize> {263 ) -> Option<usize> {249 location_to_offset(&self.get_source(file).unwrap(), line, column)264 location_to_offset(265 &self.get_source(file).expect("file not found"),266 line,267 column,268 )312 STDLIB_STR.to_owned().into(),331 STDLIB_STR.to_owned().into(),313 builtin::get_parsed_stdlib(),332 builtin::get_parsed_stdlib(),314 )333 )315 .unwrap();334 .expect("stdlib is correct");316 let val = self.evaluate_loaded_file_raw(&std_path).unwrap();335 let val = self336 .evaluate_loaded_file_raw(&std_path)337 .expect("stdlib is correct");317 self.settings_mut().globals.insert("std".into(), val);338 self.settings_mut().globals.insert("std".into(), val);318 self339 self319 }340 }342 // Error creation uses data, so i drop guard here363 // Error creation uses data, so i drop guard here343 drop(data);364 drop(data);344 throw!(StackOverflow);365 throw!(StackOverflow);345 } else {366 }346 *stack_depth += 1;367 *stack_depth += 1;347 }348 }368 }349 let result = f();369 let result = f();350 {370 {376 // Error creation uses data, so i drop guard here396 // Error creation uses data, so i drop guard here377 drop(data);397 drop(data);378 throw!(StackOverflow);398 throw!(StackOverflow);379 } else {399 }380 *stack_depth += 1;400 *stack_depth += 1;381 }382 }401 }383 let mut result = f();402 let mut result = f();384 {403 {411 // Error creation uses data, so i drop guard here430 // Error creation uses data, so i drop guard here412 drop(data);431 drop(data);413 throw!(StackOverflow);432 throw!(StackOverflow);414 } else {433 }415 *stack_depth += 1;434 *stack_depth += 1;416 }417 }435 }418 let result = f();436 let result = f();419 {437 {431 result449 result432 }450 }433451452 /// # Panics453 /// In case of formatting failure434 pub fn stringify_err(&self, e: &LocError) -> String {454 pub fn stringify_err(&self, e: &LocError) -> String {435 let mut out = String::new();455 let mut out = String::new();436 self.settings()456 self.settings()1234 assert_eval!(r#"std.assertEqual(std.count(["a", "b", "a"], "a"), 2)"#);1254 assert_eval!(r#"std.assertEqual(std.count(["a", "b", "a"], "a"), 2)"#);1235 }1255 }12361237 mod derive_typed {1238 use std::path::PathBuf;12391240 use crate::{typed::Typed, State};12411242 #[derive(PartialEq, Debug, Typed)]1243 struct MyTyped {1244 a: u32,1245 #[typed(rename = "b")]1246 c: String,1247 }12481249 #[test]1250 fn test() {1251 let es = State::default();1252 let val = eval!("{a: 14, b: 'Hello, world!'}");1253 let typed = MyTyped::try_from(val).unwrap();12541255 assert_eq!(1256 typed,1257 MyTyped {1258 a: 14,1259 c: "Hello, world!".to_string()1260 }1261 );1262 es.settings_mut()1263 .globals1264 .insert("mytyped".into(), typed.try_into().unwrap());12651266 let v = es1267 .evaluate_snippet_raw(1268 PathBuf::from("raw.jsonnet").into(),1269 "1270 mytyped == {a: 14, b: 'Hello, world!'}1271 "1272 .into(),1273 )1274 .unwrap()1275 .as_bool()1276 .unwrap();1277 assert!(v)1278 }1279 }1280}1256}12811257crates/jrsonnet-evaluator/src/map.rsdiffbeforeafterboth34 .034 .035 .parent35 .parent36 .as_ref()36 .as_ref()37 .map(|p| p.contains_key(key))37 .map_or(false, |p| p.contains_key(key))38 .unwrap_or(false)39 }38 }40}39}4140crates/jrsonnet-evaluator/src/native.rsdiffbeforeafterboth37 fn call(&self, s: State, ctx: Context, loc: CallLocation, args: &dyn ArgsLike) -> Result<Val> {37 fn call(&self, s: State, ctx: Context, loc: CallLocation, args: &dyn ArgsLike) -> Result<Val> {38 let args = parse_builtin_call(s.clone(), ctx, &self.params, args, true)?;38 let args = parse_builtin_call(s.clone(), ctx, &self.params, args, true)?;39 let mut out_args = Vec::with_capacity(self.params.len());39 let mut out_args = Vec::with_capacity(self.params.len());40 for p in self.params.iter() {40 for p in &self.params {41 out_args.push(args[&p.name].evaluate(s.clone())?);41 out_args.push(args[&p.name].evaluate(s.clone())?);42 }42 }43 self.handler.call(s, loc.0.map(|l| l.0.clone()), &out_args)43 self.handler.call(s, loc.0.map(|l| l.0.clone()), &out_args)crates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth2 cell::RefCell,2 cell::RefCell,3 fmt::Debug,3 fmt::Debug,4 hash::{Hash, Hasher},4 hash::{Hash, Hasher},5 ptr::addr_of,5};6};677use gcmodule::{Cc, Trace, Weak};8use gcmodule::{Cc, Trace, Weak};202121#[cfg(not(feature = "exp-preserve-order"))]22#[cfg(not(feature = "exp-preserve-order"))]22mod ordering {23mod ordering {24 #![allow(25 // This module works as stub for preserve-order feature26 clippy::unused_self,27 )]2823 use gcmodule::Trace;29 use gcmodule::Trace;2430899590use ordering::*;96use ordering::*;919798#[allow(clippy::module_name_repetitions)]92#[derive(Debug, Trace)]99#[derive(Debug, Trace)]93pub struct ObjMember {100pub struct ObjMember {94 pub add: bool,101 pub add: bool,113 Errored(LocError),120 Errored(LocError),114}121}115122123#[allow(clippy::module_name_repetitions)]116#[derive(Trace)]124#[derive(Trace)]117#[force_tracking]125#[force_tracking]118pub struct ObjValueInternals {126pub struct ObjValueInternals {136impl Eq for WeakObjValue {}144impl Eq for WeakObjValue {}137impl Hash for WeakObjValue {145impl Hash for WeakObjValue {138 fn hash<H: Hasher>(&self, hasher: &mut H) {146 fn hash<H: Hasher>(&self, hasher: &mut H) {139 hasher.write_usize(weak_raw(self.0.clone()) as usize)147 hasher.write_usize(weak_raw(self.0.clone()) as usize);140 }148 }141}149}142150151#[allow(clippy::module_name_repetitions)]143#[derive(Clone, Trace)]152#[derive(Clone, Trace)]144pub struct ObjValue(pub(crate) Cc<ObjValueInternals>);153pub struct ObjValue(pub(crate) Cc<ObjValueInternals>);145impl Debug for ObjValue {154impl Debug for ObjValue {178 pub fn new_empty() -> Self {187 pub fn new_empty() -> Self {179 Self::new(None, Cc::new(GcHashMap::new()), Cc::new(Vec::new()))188 Self::new(None, Cc::new(GcHashMap::new()), Cc::new(Vec::new()))180 }189 }190 #[must_use]181 pub fn extend_from(&self, super_obj: Self) -> Self {191 pub fn extend_from(&self, super_obj: Self) -> Self {182 match &self.0.super_obj {192 match &self.0.super_obj {183 None => Self::new(193 None => Self::new(201 ObjMemberBuilder::new(ExtendBuilder(self), name, FieldIndex::default())211 ObjMemberBuilder::new(ExtendBuilder(self), name, FieldIndex::default())202 }212 }213214 #[must_use]203 pub fn with_this(&self, this_obj: Self) -> Self {215 pub fn with_this(&self, this_obj: Self) -> Self {204 Self(Cc::new(ObjValueInternals {216 Self(Cc::new(ObjValueInternals {205 super_obj: self.0.super_obj.clone(),217 super_obj: self.0.super_obj.clone(),222 if !self.0.this_entries.is_empty() {234 if !self.0.this_entries.is_empty() {223 return false;235 return false;224 }236 }225 self.0237 self.0.super_obj.as_ref().map_or(true, Self::is_empty)226 .super_obj227 .as_ref()228 .map(|s| s.is_empty())229 .unwrap_or(true)230 }238 }231239232 /// Run callback for every field found in object240 /// Run callback for every field found in object254 let new_sort_key = FieldSortKey::new(depth, member.original_index);262 let new_sort_key = FieldSortKey::new(depth, member.original_index);255 match member.visibility {263 match member.visibility {256 Visibility::Normal => {264 Visibility::Normal => {257 let entry = out.entry(name.to_owned());265 let entry = out.entry(name.clone());258 let v = entry.or_insert((true, new_sort_key));266 let v = entry.or_insert((true, new_sort_key));259 v.1 = new_sort_key;267 v.1 = new_sort_key;260 }268 }261 Visibility::Hidden => {269 Visibility::Hidden => {262 out.insert(name.to_owned(), (false, new_sort_key));270 out.insert(name.clone(), (false, new_sort_key));263 }271 }264 Visibility::Unhide => {272 Visibility::Unhide => {265 out.insert(name.to_owned(), (true, new_sort_key));273 out.insert(name.clone(), (true, new_sort_key));266 }274 }267 };275 };268 false276 false356 }364 }357 pub fn has_field(&self, name: IStr) -> bool {365 pub fn has_field(&self, name: IStr) -> bool {358 self.field_visibility(name)366 self.field_visibility(name)359 .map(|v| v.is_visible())367 .map_or(false, |v| v.is_visible())360 .unwrap_or(false)361 }368 }362369363 pub fn get(&self, s: State, key: IStr) -> Result<Option<Val>> {370 pub fn get(&self, s: State, key: IStr) -> Result<Option<Val>> {459impl Eq for ObjValue {}466impl Eq for ObjValue {}460impl Hash for ObjValue {467impl Hash for ObjValue {461 fn hash<H: Hasher>(&self, hasher: &mut H) {468 fn hash<H: Hasher>(&self, hasher: &mut H) {462 hasher.write_usize(&*self.0 as *const _ as usize)469 hasher.write_usize(addr_of!(*self.0) as usize);463 }470 }464}471}465472473#[allow(clippy::module_name_repetitions)]466pub struct ObjValueBuilder {474pub struct ObjValueBuilder {467 super_obj: Option<ObjValue>,475 super_obj: Option<ObjValue>,468 map: GcHashMap<IStr, ObjMember>,476 map: GcHashMap<IStr, ObjMember>,510 }518 }511}519}512520521#[allow(clippy::module_name_repetitions)]513#[must_use = "value not added unless binding() was called"]522#[must_use = "value not added unless binding() was called"]514pub struct ObjMemberBuilder<Kind> {523pub struct ObjMemberBuilder<Kind> {515 kind: Kind,524 kind: Kind,583 CallLocation(location.as_ref()),592 CallLocation(location.as_ref()),584 || format!("field <{}> initializtion", name.clone()),593 || format!("field <{}> initializtion", name.clone()),585 || throw!(DuplicateFieldName(name.clone())),594 || throw!(DuplicateFieldName(name.clone())),586 )?595 )?;587 }596 }588 Ok(())597 Ok(())589 }598 }592pub struct ExtendBuilder<'v>(&'v mut ObjValue);601pub struct ExtendBuilder<'v>(&'v mut ObjValue);593impl<'v> ObjMemberBuilder<ExtendBuilder<'v>> {602impl<'v> ObjMemberBuilder<ExtendBuilder<'v>> {594 pub fn value(self, value: Val) {603 pub fn value(self, value: Val) {595 self.binding(LazyBinding::Bound(LazyVal::new_resolved(value)))604 self.binding(LazyBinding::Bound(LazyVal::new_resolved(value)));596 }605 }597 pub fn bindable(self, bindable: TraceBox<dyn Bindable>) {606 pub fn bindable(self, bindable: TraceBox<dyn Bindable>) {598 self.binding(LazyBinding::Bindable(Cc::new(bindable)))607 self.binding(LazyBinding::Bindable(Cc::new(bindable)));599 }608 }600 pub fn binding(self, binding: LazyBinding) {609 pub fn binding(self, binding: LazyBinding) {601 let (receiver, name, member) = self.build_member(binding);610 let (receiver, name, member) = self.build_member(binding);602 let new = receiver.0.clone();611 let new = receiver.0.clone();603 *receiver.0 = new.extend_with_raw_member(name, member)612 *receiver.0 = new.extend_with_raw_member(name, member);604 }613 }605}614}606615crates/jrsonnet-evaluator/src/trace/location.rsdiffbeforeafterboth1#[allow(clippy::module_name_repetitions)]1#[derive(Clone, PartialEq, Debug)]2#[derive(Clone, PartialEq, Debug)]2pub struct CodeLocation {3pub struct CodeLocation {3 pub offset: usize,4 pub offset: usize,9 pub line_end_offset: usize,10 pub line_end_offset: usize,10}11}111213#[allow(clippy::module_name_repetitions)]12pub fn location_to_offset(mut file: &str, mut line: usize, column: usize) -> Option<usize> {14pub fn location_to_offset(mut file: &str, mut line: usize, column: usize) -> Option<usize> {13 let mut offset = 0;15 let mut offset = 0;14 while line > 1 {16 while line > 1 {21 Some(offset)23 Some(offset)22}24}232526#[allow(clippy::module_name_repetitions)]24pub fn offset_to_location(file: &str, offsets: &[usize]) -> Vec<CodeLocation> {27pub fn offset_to_location(file: &str, offsets: &[usize]) -> Vec<CodeLocation> {25 if offsets.is_empty() {28 if offsets.is_empty() {26 return vec![];29 return vec![];27 }30 }28 let mut line = 1;31 let mut line = 1;29 let mut column = 1;32 let mut column = 1;30 let max_offset = *offsets.iter().max().unwrap();33 let max_offset = *offsets.iter().max().expect("offsets is not empty");313432 let mut offset_map = offsets35 let mut offset_map = offsets33 .iter()36 .iter()crates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth19impl PathResolver {19impl PathResolver {20 pub fn resolve(&self, from: &Path) -> String {20 pub fn resolve(&self, from: &Path) -> String {21 match self {21 match self {22 Self::FileName => from.file_name().unwrap().to_string_lossy().into_owned(),22 Self::FileName => from23 .file_name()24 .expect("file name exists")25 .to_string_lossy()26 .into_owned(),23 Self::Absolute => from.to_string_lossy().into_owned(),27 Self::Absolute => from.to_string_lossy().into_owned(),26 return from.to_string_lossy().into_owned();30 return from.to_string_lossy().into_owned();27 }31 }28 pathdiff::diff_paths(from, base)32 pathdiff::diff_paths(from, base)29 .unwrap()33 .expect("base is absolute")30 .to_string_lossy()34 .to_string_lossy()31 .into_owned()35 .into_owned()32 }36 }35}39}364037/// Implements pretty-printing of traces41/// Implements pretty-printing of traces42#[allow(clippy::module_name_repetitions)]38pub trait TraceFormat {43pub trait TraceFormat {39 fn write_trace(44 fn write_trace(40 &self,45 &self,88 error,93 error,89 } = error.error()94 } = error.error()90 {95 {91 writeln!(out)?;92 use std::fmt::Write;96 use std::fmt::Write;9798 writeln!(out)?;93 let mut n = self.resolver.resolve(path);99 let mut n = self.resolver.resolve(path);94 let mut offset = error.location.offset;100 let mut offset = error.location.offset;95 let is_eof = if offset >= source_code.len() {101 let is_eof = if offset >= source_code.len() {134 let align = file_names140 let align = file_names135 .iter()141 .iter()136 .flatten()142 .flatten()137 .map(|e| e.len())143 .map(String::len)138 .max()144 .max()139 .unwrap_or(0);145 .unwrap_or(0);140 for (el, file) in error.trace().0.iter().zip(file_names) {146 for (el, file) in error.trace().0.iter().zip(file_names) {166 error: &LocError,172 error: &LocError,167 ) -> Result<(), std::fmt::Error> {173 ) -> Result<(), std::fmt::Error> {168 write!(out, "{}", error.error())?;174 write!(out, "{}", error.error())?;169 for item in error.trace().0.iter() {175 for item in &error.trace().0 {170 writeln!(out)?;176 writeln!(out)?;171 let desc = &item.desc;177 let desc = &item.desc;172 if let Some(source) = &item.location {178 if let Some(source) = &item.location {227 )?;233 )?;228 }234 }229 let trace = &error.trace();235 let trace = &error.trace();230 for item in trace.0.iter() {236 for item in &trace.0 {231 writeln!(out)?;237 writeln!(out)?;232 let desc = &item.desc;238 let desc = &item.desc;233 if let Some(source) = &item.location {239 if let Some(source) = &item.location {273 let snippet = Snippet {279 let snippet = Snippet {274 opt: FormatOptions {280 opt: FormatOptions {275 color: true,281 color: true,276 ..Default::default()282 ..FormatOptions::default()277 },283 },278 title: None,284 title: None,279 footer: vec![],285 footer: vec![],crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth38 <Self as Typed>::TYPE.check(s, &value)?;38 <Self as Typed>::TYPE.check(s, &value)?;39 match value {39 match value {40 Val::Num(n) => {40 Val::Num(n) => {41 #[allow(clippy::float_cmp)]41 if n.trunc() != n {42 if n.trunc() != n {42 throw!(RuntimeError(43 throw!(RuntimeError(43 format!(44 format!(95 <Self as Typed>::TYPE.check(s, &value)?;96 <Self as Typed>::TYPE.check(s, &value)?;96 match value {97 match value {97 Val::Num(n) => {98 Val::Num(n) => {99 #[allow(clippy::float_cmp)]98 if n.trunc() != n {100 if n.trunc() != n {99 throw!(RuntimeError(101 throw!(RuntimeError(100 format!(102 format!(160impl Typed for usize {162impl Typed for usize {161 // It is possible to store 54 bits of precision in f64, but leaving u32::MAX here for compatibility163 // It is possible to store 54 bits of precision in f64, but leaving u32::MAX here for compatibility162 const TYPE: &'static ComplexValType =164 const TYPE: &'static ComplexValType =163 &ComplexValType::BoundedNumber(Some(0.0), Some(4294967295.0));165 &ComplexValType::BoundedNumber(Some(0.0), Some(u32::MAX as f64));164166165 fn into_untyped(value: Self, _: State) -> Result<Val> {167 fn into_untyped(value: Self, _: State) -> Result<Val> {166 if value > u32::MAX as Self {168 if value > u32::MAX as Self {173 <Self as Typed>::TYPE.check(s, &value)?;175 <Self as Typed>::TYPE.check(s, &value)?;174 match value {176 match value {175 Val::Num(n) => {177 Val::Num(n) => {178 #[allow(clippy::float_cmp)]176 if n.trunc() != n {179 if n.trunc() != n {177 throw!(RuntimeError(180 throw!(RuntimeError(178 "cannot convert number with fractional part to usize".into()181 "cannot convert number with fractional part to usize".into()263}266}264267265/// To be used in Vec<Any>268/// To be used in Vec<Any>266/// Regular Val can't be used here, because it has wrong TryFrom::Error type269/// Regular Val can't be used here, because it has wrong `TryFrom::Error` type267#[derive(Clone)]270#[derive(Clone)]268pub struct Any(pub Val);271pub struct Any(pub Val);269272279 }282 }280}283}281284282/// Specialization, provides faster TryFrom<VecVal> for Val285/// Specialization, provides faster `TryFrom<VecVal>` for Val283pub struct VecVal(pub Cc<Vec<Val>>);286pub struct VecVal(pub Cc<Vec<Val>>);284287285impl Typed for VecVal {288impl Typed for VecVal {310 }313 }311314312 fn from_untyped(value: Val, s: State) -> Result<Self> {315 fn from_untyped(value: Val, s: State) -> Result<Self> {313 match value {316 if let Val::Arr(ArrValue::Bytes(bytes)) = value {314 Val::Arr(ArrValue::Bytes(bytes)) => Ok(Self(bytes)),317 return Ok(Self(bytes));315 _ => {318 }316 <Self as Typed>::TYPE.check(s.clone(), &value)?;319 <Self as Typed>::TYPE.check(s.clone(), &value)?;317 match value {320 match value {318 Val::Arr(a) => {321 Val::Arr(a) => {325 }328 }326 _ => unreachable!(),329 _ => unreachable!(),327 }330 }328 }329 }330 }331 }331}332}332333crates/jrsonnet-evaluator/src/typed/mod.rsdiffbeforeafterboth71 if line.trim().is_empty() {71 if line.trim().is_empty() {72 continue;72 continue;73 }73 }74 if i != 0 {74 if i == 0 {75 writeln!(f)?;76 write!(f, " ")?;75 write!(f, " - ")?;77 } else {76 } else {77 writeln!(f)?;78 write!(f, " - ")?;78 write!(f, " ")?;79 }79 }80 write!(f, "{}", line)?;80 write!(f, "{}", line)?;81 }81 }94 Ok(_) => Ok(()),94 Ok(_) => Ok(()),95 Err(mut e) => {95 Err(mut e) => {96 if let Error::TypeError(e) = &mut e.error_mut() {96 if let Error::TypeError(e) = &mut e.error_mut() {97 (e.1).0.push(path())97 (e.1).0.push(path());98 }98 }99 Err(e)99 Err(e)100 }100 }145}145}146146147impl CheckType for ComplexValType {147impl CheckType for ComplexValType {148 #[allow(clippy::too_many_lines)]148 fn check(&self, s: State, value: &Val) -> Result<()> {149 fn check(&self, s: State, value: &Val) -> Result<()> {149 match self {150 match self {150 Self::Any => Ok(()),151 Self::Any => Ok(()),202 || format!("property {}", k),203 || format!("property {}", k),203 || ValuePathItem::Field((*k).into()),204 || ValuePathItem::Field((*k).into()),204 || v.check(s.clone(), &got_v),205 || v.check(s.clone(), &got_v),205 )?206 )?;206 } else {207 } else {207 return Err(208 return Err(208 TypeError::MissingProperty((*k).into(), self.clone()).into()209 TypeError::MissingProperty((*k).into(), self.clone()).into()245 }246 }246 Self::Sum(types) => {247 Self::Sum(types) => {247 for ty in types.iter() {248 for ty in types.iter() {248 ty.check(s.clone(), value)?249 ty.check(s.clone(), value)?;249 }250 }250 Ok(())251 Ok(())251 }252 }252 Self::SumRef(types) => {253 Self::SumRef(types) => {253 for ty in types.iter() {254 for ty in types.iter() {254 ty.check(s.clone(), value)?255 ty.check(s.clone(), value)?;255 }256 }256 Ok(())257 Ok(())257 }258 }crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth32 Pending,32 Pending,33}33}343435#[allow(clippy::module_name_repetitions)]35#[derive(Clone, Trace)]36#[derive(Clone, Trace)]36pub struct LazyVal(Cc<RefCell<LazyValInternals>>);37pub struct LazyVal(Cc<RefCell<LazyValInternals>>);37impl LazyVal {38impl LazyVal {50 LazyValInternals::Computed(v) => return Ok(v.clone()),51 LazyValInternals::Computed(v) => return Ok(v.clone()),51 LazyValInternals::Errored(e) => return Err(e.clone()),52 LazyValInternals::Errored(e) => return Err(e.clone()),52 LazyValInternals::Pending => return Err(InfiniteRecursionDetected.into()),53 LazyValInternals::Pending => return Err(InfiniteRecursionDetected.into()),53 _ => (),54 LazyValInternals::Waiting(..) => (),54 };55 };55 let value = if let LazyValInternals::Waiting(value) =56 let value = if let LazyValInternals::Waiting(value) =56 std::mem::replace(&mut *self.0.borrow_mut(), LazyValInternals::Pending)57 std::mem::replace(&mut *self.0.borrow_mut(), LazyValInternals::Pending)114 }115 }115}116}116117118#[allow(clippy::module_name_repetitions)]117#[derive(Trace, Clone)]119#[derive(Trace, Clone)]118pub enum FuncVal {120pub enum FuncVal {119 /// Plain function implemented in jsonnet121 /// Plain function implemented in jsonnet225 let rem = diff % self.step();227 let rem = diff % self.step();226 let div = diff / self.step();228 let div = diff / self.step();227229228 if rem != 0 {230 if rem == 0 {229 div + 1231 div230 } else {232 } else {231 div233 div + 1232 }234 }233 }235 }234}236}249 Self::Eager(Cc::new(Vec::new()))251 Self::Eager(Cc::new(Vec::new()))250 }252 }253254 /// # Panics255 /// If a > b251 pub fn new_range(a: i32, b: i32) -> Self {256 pub fn new_range(a: i32, b: i32) -> Self {252 assert!(a <= b);257 assert!(a <= b);253 Self::Range(a, b)258 Self::Range(a, b)254 }259 }255260261 /// # Panics262 /// If passed numbers are incorrect263 #[must_use]256 pub fn slice(self, from: Option<usize>, to: Option<usize>, step: Option<usize>) -> Self {264 pub fn slice(self, from: Option<usize>, to: Option<usize>, step: Option<usize>) -> Self {257 let len = self.len();265 let len = self.len();258 let from = from.unwrap_or(0);266 let from = from.unwrap_or(0);289 match self {297 match self {290 Self::Bytes(i) => i298 Self::Bytes(i) => i291 .get(index)299 .get(index)292 .map_or(Ok(None), |v| Ok(Some(Val::Num(*v as f64)))),300 .map_or(Ok(None), |v| Ok(Some(Val::Num(f64::from(*v))))),293 Self::Lazy(vec) => {301 Self::Lazy(vec) => {294 if let Some(v) = vec.get(index) {302 if let Some(v) = vec.get(index) {295 Ok(Some(v.evaluate(s)?))303 Ok(Some(v.evaluate(s)?))333 match self {341 match self {334 Self::Bytes(i) => i342 Self::Bytes(i) => i335 .get(index)343 .get(index)336 .map(|b| LazyVal::new_resolved(Val::Num(*b as f64))),344 .map(|b| LazyVal::new_resolved(Val::Num(f64::from(*b)))),337 Self::Lazy(vec) => vec.get(index).cloned(),345 Self::Lazy(vec) => vec.get(index).cloned(),338 Self::Eager(vec) => vec.get(index).cloned().map(LazyVal::new_resolved),346 Self::Eager(vec) => vec.get(index).cloned().map(LazyVal::new_resolved),339 Self::Extended(v) => {347 Self::Extended(v) => {374 Self::Bytes(i) => {382 Self::Bytes(i) => {375 let mut out = Vec::with_capacity(i.len());383 let mut out = Vec::with_capacity(i.len());376 for v in i.iter() {384 for v in i.iter() {377 out.push(Val::Num(*v as f64));385 out.push(Val::Num(f64::from(*v)));378 }386 }379 Cc::new(out)387 Cc::new(out)380 }388 }396 Self::Range(a, b) => {404 Self::Range(a, b) => {397 let mut out = Vec::with_capacity(self.len());405 let mut out = Vec::with_capacity(self.len());398 for i in *a..*b {406 for i in *a..*b {399 out.push(Val::Num(i as f64));407 out.push(Val::Num(f64::from(i)));400 }408 }401 Cc::new(out)409 Cc::new(out)402 }410 }414 .take(v.to() - v.from())422 .take(v.to() - v.from())415 .step_by(v.step())423 .step_by(v.step())416 {424 {417 out.push(v.evaluate(s.clone())?)425 out.push(v.evaluate(s.clone())?);418 }426 }419 Cc::new(out)427 Cc::new(out)420 }428 }423431424 pub fn iter(&self, s: State) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {432 pub fn iter(&self, s: State) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {425 (0..self.len()).map(move |idx| match self {433 (0..self.len()).map(move |idx| match self {426 Self::Bytes(b) => Ok(Val::Num(b[idx] as f64)),434 Self::Bytes(b) => Ok(Val::Num(f64::from(b[idx]))),427 Self::Lazy(l) => l[idx].evaluate(s.clone()),435 Self::Lazy(l) => l[idx].evaluate(s.clone()),428 Self::Eager(e) => Ok(e[idx].clone()),436 Self::Eager(e) => Ok(e[idx].clone()),429 Self::Extended(_) => self.get(s.clone(), idx).map(|e| e.unwrap()),430 Self::Range(..) => self.get(s.clone(), idx).map(|e| e.unwrap()),437 Self::Extended(..) | Self::Range(..) | Self::Reversed(..) | Self::Slice(..) => {431 Self::Reversed(..) => self.get(s.clone(), idx).map(|e| e.unwrap()),432 Self::Slice(..) => self.get(s.clone(), idx).map(|e| e.unwrap()),438 self.get(s.clone(), idx).map(|e| e.expect("idx < len"))439 }433 })440 })434 }441 }435442436 pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {443 pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {437 (0..self.len()).map(move |idx| match self {444 (0..self.len()).map(move |idx| match self {438 Self::Bytes(b) => LazyVal::new_resolved(Val::Num(b[idx] as f64)),445 Self::Bytes(b) => LazyVal::new_resolved(Val::Num(f64::from(b[idx]))),439 Self::Lazy(l) => l[idx].clone(),446 Self::Lazy(l) => l[idx].clone(),440 Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),447 Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),441 Self::Extended(_) => self.get_lazy(idx).unwrap(),442 Self::Range(..) => self.get_lazy(idx).unwrap(),448 Self::Slice(..) | Self::Extended(..) | Self::Range(..) | Self::Reversed(..) => {443 Self::Reversed(..) => self.get_lazy(idx).unwrap(),444 Self::Slice(..) => self.get_lazy(idx).unwrap(),449 self.get_lazy(idx).expect("idx < len")450 }445 })451 })446 }452 }447453454 #[must_use]448 pub fn reversed(self) -> Self {455 pub fn reversed(self) -> Self {449 Self::Reversed(Box::new(self))456 Self::Reversed(Box::new(self))450 }457 }493 }500 }494}501}495502503#[allow(clippy::module_name_repetitions)]496pub enum IndexableVal {504pub enum IndexableVal {497 Str(IStr),505 Str(IStr),498 Arr(ArrValue),506 Arr(ArrValue),708 preserve_order,716 preserve_order,709 },717 },710 )718 )711 .map(|s| s.into())719 .map(Into::into)712 }720 }713721714 /// Calls `std.manifestJson`722 /// Calls `std.manifestJson`730 preserve_order,738 preserve_order,731 },739 },732 )740 )733 .map(|s| s.into())741 .map(Into::into)734 }742 }735743736 pub fn to_yaml(744 pub fn to_yaml(751 preserve_order,759 preserve_order,752 },760 },753 )761 )754 .map(|s| s.into())762 .map(Into::into)755 }763 }756 pub fn into_indexable(self) -> Result<IndexableVal> {764 pub fn into_indexable(self) -> Result<IndexableVal> {757 Ok(match self {765 Ok(match self {824 for field in fields {832 for field in fields {825 if !equals(833 if !equals(826 s.clone(),834 s.clone(),827 &a.get(s.clone(), field.clone())?.unwrap(),835 &a.get(s.clone(), field.clone())?.expect("field exists"),828 &b.get(s.clone(), field)?.unwrap(),836 &b.get(s.clone(), field)?.expect("field exists"),829 )? {837 )? {830 return Ok(false);838 return Ok(false);831 }839 }crates/jrsonnet-evaluator/tests/common.rsdiffbeforeafterboth11 }};11 }};12}12}1314#[macro_export]15macro_rules! ensure {16 ($v:expr $(,)?) => {17 if !$v {18 ::jrsonnet_evaluator::throw_runtime!("assertion failed: {}", stringify!($v))19 }20 };21}132214#[macro_export]23#[macro_export]15macro_rules! ensure_val_eq {24macro_rules! ensure_val_eq {crates/jrsonnet-evaluator/tests/sanity.rsdiffbeforeafterbothno changes
crates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth157 });157 });158 }158 }159159160 match &ty as &Type {160 match ty as &Type {161 Type::Reference(r) if type_is_path(&r.elem, &name).is_some() => return Ok(Self::This),161 Type::Reference(r) if type_is_path(&r.elem, name).is_some() => return Ok(Self::This),162 _ => {}162 _ => {}163 }163 }164164465 "strategy should be set when flattening Option",465 "strategy should be set when flattening Option",466 ));466 ));467 }467 }468 } else {468 } else if attr.flatten_ok {469 if attr.flatten_ok {470 return Err(Error::new(469 return Err(Error::new(471 field.span(),470 field.span(),472 "flatten(ok) is only useable on optional fields",471 "flatten(ok) is only useable on optional fields",473 ));472 ));474 }473 }475 }474476 Ok(Self {475 Ok(Self {477 attr,476 attr,478 ident,477 ident,