1use std::{cell::RefCell, rc::Rc};23use jrsonnet_evaluator::{4 error::{Error::*, Result},5 function::{builtin, ArgLike, CallLocation, FuncVal},6 throw,7 typed::{Any, 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]) -> Result<usize> {16 use Either4::*;17 Ok(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<Any> {29 let ctx = ctx.state().create_default_context(extvar_source(&x, ""));30 Ok(Any(this31 .settings32 .borrow()33 .ext_vars34 .get(&x)35 .cloned()36 .ok_or_else(|| UndefinedExternalVariable(x))?37 .evaluate_arg(ctx, true)?38 .evaluate()?))39}4041#[builtin(fields(42 settings: Rc<RefCell<Settings>>,43))]44pub fn builtin_native(this: &builtin_native, name: IStr) -> Result<Any> {45 Ok(Any(this46 .settings47 .borrow()48 .ext_natives49 .get(&name)50 .cloned()51 .map_or(Val::Null, |v| {52 Val::Func(FuncVal::Builtin(v.clone()))53 })))54}5556#[builtin(fields(57 settings: Rc<RefCell<Settings>>,58))]59pub fn builtin_trace(60 this: &builtin_trace,61 loc: CallLocation,62 str: IStr,63 rest: Thunk<Val>,64) -> Result<Any> {65 this.settings.borrow().trace_printer.print_trace(loc, str);66 Ok(Any(rest.evaluate()?))67}6869#[allow(clippy::comparison_chain)]70#[builtin]71pub fn builtin_starts_with(a: Either![IStr, ArrValue], b: Either![IStr, ArrValue]) -> Result<bool> {72 Ok(match (a, b) {73 (Either2::A(a), Either2::A(b)) => a.starts_with(b.as_str()),74 (Either2::B(a), Either2::B(b)) => {75 if b.len() > a.len() {76 return Ok(false);77 } else if b.len() == a.len() {78 return equals(&Val::Arr(a), &Val::Arr(b));79 } else {80 for (a, b) in a.slice(None, Some(b.len()), None).iter().zip(b.iter()) {81 let a = a?;82 let b = b?;83 if !equals(&a, &b)? {84 return Ok(false);85 }86 }87 true88 }89 }90 _ => throw!("both arguments should be of the same type"),91 })92}9394#[allow(clippy::comparison_chain)]95#[builtin]96pub fn builtin_ends_with(a: Either![IStr, ArrValue], b: Either![IStr, ArrValue]) -> Result<bool> {97 Ok(match (a, b) {98 (Either2::A(a), Either2::A(b)) => a.ends_with(b.as_str()),99 (Either2::B(a), Either2::B(b)) => {100 if b.len() > a.len() {101 return Ok(false);102 } else if b.len() == a.len() {103 return equals(&Val::Arr(a), &Val::Arr(b));104 } else {105 let a_len = a.len();106 for (a, b) in a107 .slice(Some(a_len - b.len()), None, None)108 .iter()109 .zip(b.iter())110 {111 let a = a?;112 let b = b?;113 if !equals(&a, &b)? {114 return Ok(false);115 }116 }117 true118 }119 }120 _ => throw!("both arguments should be of the same type"),121 })122}