1use std::{cell::RefCell, rc::Rc};23use jrsonnet_evaluator::{4 error::{ErrorKind::*, Result},5 function::{builtin, ArgLike, CallLocation, FuncVal},6 throw,7 typed::{Either2, Either4},8 val::{equals, ArrValue},9 Context, Either, IStr, ObjValue, Thunk, Val,10};1112use crate::{extvar_source, Settings};1314#[builtin]15pub fn builtin_length(x: Either![IStr, ArrValue, ObjValue, FuncVal]) -> usize {16 use Either4::*;17 match x {18 A(x) => x.chars().count(),19 B(x) => x.len(),20 C(x) => x.len(),21 D(f) => f.params_len(),22 }23}2425#[builtin(fields(26 settings: Rc<RefCell<Settings>>,27))]28pub fn builtin_ext_var(this: &builtin_ext_var, ctx: Context, x: IStr) -> Result<Val> {29 let ctx = ctx.state().create_default_context(extvar_source(&x, ""));30 this.settings31 .borrow()32 .ext_vars33 .get(&x)34 .cloned()35 .ok_or_else(|| UndefinedExternalVariable(x))?36 .evaluate_arg(ctx, true)?37 .evaluate()38}3940#[builtin(fields(41 settings: Rc<RefCell<Settings>>,42))]43pub fn builtin_native(this: &builtin_native, x: IStr) -> Val {44 this.settings45 .borrow()46 .ext_natives47 .get(&x)48 .cloned()49 .map_or(Val::Null, |v| Val::Func(FuncVal::Builtin(v)))50}5152#[builtin(fields(53 settings: Rc<RefCell<Settings>>,54))]55pub fn builtin_trace(56 this: &builtin_trace,57 loc: CallLocation,58 str: IStr,59 rest: Thunk<Val>,60) -> Result<Val> {61 this.settings.borrow().trace_printer.print_trace(loc, str);62 rest.evaluate()63}6465#[allow(clippy::comparison_chain)]66#[builtin]67pub fn builtin_starts_with(a: Either![IStr, ArrValue], b: Either![IStr, ArrValue]) -> Result<bool> {68 Ok(match (a, b) {69 (Either2::A(a), Either2::A(b)) => a.starts_with(b.as_str()),70 (Either2::B(a), Either2::B(b)) => {71 if b.len() > a.len() {72 return Ok(false);73 } else if b.len() == a.len() {74 return equals(&Val::Arr(a), &Val::Arr(b));75 } else {76 for (a, b) in a.iter().take(b.len()).zip(b.iter()) {77 let a = a?;78 let b = b?;79 if !equals(&a, &b)? {80 return Ok(false);81 }82 }83 true84 }85 }86 _ => throw!("both arguments should be of the same type"),87 })88}8990#[allow(clippy::comparison_chain)]91#[builtin]92pub fn builtin_ends_with(a: Either![IStr, ArrValue], b: Either![IStr, ArrValue]) -> Result<bool> {93 Ok(match (a, b) {94 (Either2::A(a), Either2::A(b)) => a.ends_with(b.as_str()),95 (Either2::B(a), Either2::B(b)) => {96 if b.len() > a.len() {97 return Ok(false);98 } else if b.len() == a.len() {99 return equals(&Val::Arr(a), &Val::Arr(b));100 } else {101 let a_len = a.len();102 for (a, b) in a.iter().skip(a_len - b.len()).zip(b.iter()) {103 let a = a?;104 let b = b?;105 if !equals(&a, &b)? {106 return Ok(false);107 }108 }109 true110 }111 }112 _ => throw!("both arguments should be of the same type"),113 })114}