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

difftreelog

source

crates/jrsonnet-stdlib/src/misc.rs3.2 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]27pub fn builtin_get(28	o: ObjValue,29	f: IStr,30	default: Option<Thunk<Val>>,31	#[default(true)]32	inc_hidden: bool,33) -> Result<Val> {34	let do_default = move || {35		let Some(default) = default else {36			return Ok(Val::Null);37		};38		default.evaluate()39	};40	// Happy path for invisible fields41	if !inc_hidden && !o.has_field_ex(f.clone(), false) {42		return do_default();43	}44	let Some(v) = o.get(f)? else {45		return do_default();46	};47	Ok(v)48}4950#[builtin(fields(51	settings: Rc<RefCell<Settings>>,52))]53pub fn builtin_ext_var(this: &builtin_ext_var, ctx: Context, x: IStr) -> Result<Val> {54	let ctx = ctx.state().create_default_context(extvar_source(&x, ""));55	this.settings56		.borrow()57		.ext_vars58		.get(&x)59		.cloned()60		.ok_or_else(|| UndefinedExternalVariable(x))?61		.evaluate_arg(ctx, true)?62		.evaluate()63}6465#[builtin(fields(66	settings: Rc<RefCell<Settings>>,67))]68pub fn builtin_native(this: &builtin_native, x: IStr) -> Val {69	this.settings70		.borrow()71		.ext_natives72		.get(&x)73		.cloned()74		.map_or(Val::Null, Val::Func)75}7677#[builtin(fields(78	settings: Rc<RefCell<Settings>>,79))]80pub fn builtin_trace(81	this: &builtin_trace,82	loc: CallLocation,83	str: Val,84	rest: Option<Thunk<Val>>,85) -> Result<Val> {86	this.settings.borrow().trace_printer.print_trace(87		loc,88		match &str {89			Val::Str(s) => s.clone().into_flat(),90			Val::Func(f) => format!("{f:?}").into(),91			v => v.manifest(JsonFormat::debug())?.into(),92		},93	);94	rest.map_or_else(|| Ok(str), |rest| rest.evaluate())95}9697#[allow(clippy::comparison_chain)]98#[builtin]99pub fn builtin_starts_with(a: Either![IStr, ArrValue], b: Either![IStr, ArrValue]) -> Result<bool> {100	Ok(match (a, b) {101		(Either2::A(a), Either2::A(b)) => a.starts_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			for (a, b) in a.iter().take(b.len()).zip(b.iter()) {109				let a = a?;110				let b = b?;111				if !equals(&a, &b)? {112					return Ok(false);113				}114			}115			true116		}117		_ => bail!("both arguments should be of the same type"),118	})119}120121#[allow(clippy::comparison_chain)]122#[builtin]123pub fn builtin_ends_with(a: Either![IStr, ArrValue], b: Either![IStr, ArrValue]) -> Result<bool> {124	Ok(match (a, b) {125		(Either2::A(a), Either2::A(b)) => a.ends_with(b.as_str()),126		(Either2::B(a), Either2::B(b)) => {127			if b.len() > a.len() {128				return Ok(false);129			} else if b.len() == a.len() {130				return equals(&Val::Arr(a), &Val::Arr(b));131			}132			let a_len = a.len();133			for (a, b) in a.iter().skip(a_len - b.len()).zip(b.iter()) {134				let a = a?;135				let b = b?;136				if !equals(&a, &b)? {137					return Ok(false);138				}139			}140			true141		}142		_ => bail!("both arguments should be of the same type"),143	})144}