git.delta.rocks / jrsonnet / refs/commits / f319c3545168

difftreelog

source

crates/jrsonnet-stdlib/src/misc.rs2.8 KiBsourcehistory
1use std::{cell::RefCell, rc::Rc};23use jrsonnet_evaluator::{4	bail,5	error::{ErrorKind::*, Result},6	function::{builtin, ArgLike, CallLocation, FuncVal},7	manifest::JsonFormat,8	typed::{Either2, Either4},9	val::{equals, ArrValue},10	Context, Either, IStr, ObjValue, Thunk, Val,11};1213use crate::{extvar_source, Settings};1415#[builtin]16pub fn builtin_length(x: Either![IStr, ArrValue, ObjValue, FuncVal]) -> usize {17	use Either4::*;18	match x {19		A(x) => x.chars().count(),20		B(x) => x.len(),21		C(x) => x.len(),22		D(f) => f.params_len(),23	}24}2526#[builtin(fields(27	settings: Rc<RefCell<Settings>>,28))]29pub fn builtin_ext_var(this: &builtin_ext_var, ctx: Context, x: IStr) -> Result<Val> {30	let ctx = ctx.state().create_default_context(extvar_source(&x, ""));31	this.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, x: IStr) -> Val {45	this.settings46		.borrow()47		.ext_natives48		.get(&x)49		.cloned()50		.map_or(Val::Null, Val::Func)51}5253#[builtin(fields(54	settings: Rc<RefCell<Settings>>,55))]56pub fn builtin_trace(57	this: &builtin_trace,58	loc: CallLocation,59	str: Val,60	rest: Option<Thunk<Val>>,61) -> Result<Val> {62	this.settings.borrow().trace_printer.print_trace(63		loc,64		match &str {65			Val::Str(s) => s.clone().into_flat(),66			Val::Func(f) => format!("{f:?}").into(),67			v => v.manifest(JsonFormat::debug())?.into(),68		},69	);70	rest.map_or_else(|| Ok(str), |rest| rest.evaluate())71}7273#[allow(clippy::comparison_chain)]74#[builtin]75pub fn builtin_starts_with(a: Either![IStr, ArrValue], b: Either![IStr, ArrValue]) -> Result<bool> {76	Ok(match (a, b) {77		(Either2::A(a), Either2::A(b)) => a.starts_with(b.as_str()),78		(Either2::B(a), Either2::B(b)) => {79			if b.len() > a.len() {80				return Ok(false);81			} else if b.len() == a.len() {82				return equals(&Val::Arr(a), &Val::Arr(b));83			}84			for (a, b) in a.iter().take(b.len()).zip(b.iter()) {85				let a = a?;86				let b = b?;87				if !equals(&a, &b)? {88					return Ok(false);89				}90			}91			true92		}93		_ => bail!("both arguments should be of the same type"),94	})95}9697#[allow(clippy::comparison_chain)]98#[builtin]99pub fn builtin_ends_with(a: Either![IStr, ArrValue], b: Either![IStr, ArrValue]) -> Result<bool> {100	Ok(match (a, b) {101		(Either2::A(a), Either2::A(b)) => a.ends_with(b.as_str()),102		(Either2::B(a), Either2::B(b)) => {103			if b.len() > a.len() {104				return Ok(false);105			} else if b.len() == a.len() {106				return equals(&Val::Arr(a), &Val::Arr(b));107			}108			let a_len = a.len();109			for (a, b) in a.iter().skip(a_len - b.len()).zip(b.iter()) {110				let a = a?;111				let b = b?;112				if !equals(&a, &b)? {113					return Ok(false);114				}115			}116			true117		}118		_ => bail!("both arguments should be of the same type"),119	})120}