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

difftreelog

source

crates/jrsonnet-stdlib/src/arrays.rs5.2 KiBsourcehistory
1use jrsonnet_evaluator::{2	error::{ErrorKind::RuntimeError, Result},3	function::{builtin, FuncVal},4	throw,5	typed::{Any, BoundedI32, BoundedUsize, Either2, NativeFn, Typed},6	val::{equals, ArrValue, IndexableVal, StrValue},7	Either, IStr, Val,8};9use jrsonnet_gcmodule::Cc;1011#[builtin]12pub fn builtin_make_array(sz: BoundedI32<0, { i32::MAX }>, func: FuncVal) -> Result<ArrValue> {13	if *sz == 0 {14		return Ok(ArrValue::empty());15	}16	if let Some(trivial) = func.evaluate_trivial() {17		let mut out = Vec::with_capacity(*sz as usize);18		for _ in 0..*sz {19			out.push(trivial.clone())20		}21		Ok(ArrValue::eager(Cc::new(out)))22	} else {23		Ok(ArrValue::range_exclusive(0, *sz).map(func))24	}25}2627#[builtin]28pub fn builtin_repeat(what: Either![IStr, ArrValue], count: usize) -> Result<Any> {29	Ok(Any(match what {30		Either2::A(s) => Val::Str(StrValue::Flat(s.repeat(count).into())),31		Either2::B(arr) => Val::Arr(32			ArrValue::repeated(arr, count)33				.ok_or_else(|| RuntimeError("repeated length overflow".into()))?,34		),35	}))36}3738#[builtin]39pub fn builtin_slice(40	indexable: IndexableVal,41	index: Option<BoundedUsize<0, { i32::MAX as usize }>>,42	end: Option<BoundedUsize<0, { i32::MAX as usize }>>,43	step: Option<BoundedUsize<1, { i32::MAX as usize }>>,44) -> Result<Any> {45	indexable.slice(index, end, step).map(Val::from).map(Any)46}4748#[builtin]49pub fn builtin_map(func: FuncVal, arr: ArrValue) -> Result<ArrValue> {50	Ok(arr.map(func))51}5253#[builtin]54pub fn builtin_flatmap(55	func: NativeFn<((Either![String, Any],), Any)>,56	arr: IndexableVal,57) -> Result<IndexableVal> {58	use std::fmt::Write;59	match arr {60		IndexableVal::Str(str) => {61			let mut out = String::new();62			for c in str.chars() {63				match func(Either2::A(c.to_string()))?.0 {64					Val::Str(o) => write!(out, "{o}").unwrap(),65					Val::Null => continue,66					_ => throw!("in std.join all items should be strings"),67				};68			}69			Ok(IndexableVal::Str(out.into()))70		}71		IndexableVal::Arr(a) => {72			let mut out = Vec::new();73			for el in a.iter() {74				let el = el?;75				match func(Either2::B(Any(el)))?.0 {76					Val::Arr(o) => {77						for oe in o.iter() {78							out.push(oe?);79						}80					}81					Val::Null => continue,82					_ => throw!("in std.join all items should be arrays"),83				};84			}85			Ok(IndexableVal::Arr(out.into()))86		}87	}88}8990#[builtin]91pub fn builtin_filter(func: FuncVal, arr: ArrValue) -> Result<ArrValue> {92	arr.filter(|val| bool::from_untyped(func.evaluate_simple(&(Any(val.clone()),))?))93}9495#[builtin]96pub fn builtin_foldl(func: FuncVal, arr: ArrValue, init: Any) -> Result<Any> {97	let mut acc = init.0;98	for i in arr.iter() {99		acc = func.evaluate_simple(&(Any(acc), Any(i?)))?;100	}101	Ok(Any(acc))102}103104#[builtin]105pub fn builtin_foldr(func: FuncVal, arr: ArrValue, init: Any) -> Result<Any> {106	let mut acc = init.0;107	for i in arr.iter().rev() {108		acc = func.evaluate_simple(&(Any(i?), Any(acc)))?;109	}110	Ok(Any(acc))111}112113#[builtin]114pub fn builtin_range(from: i32, to: i32) -> Result<ArrValue> {115	if to < from {116		return Ok(ArrValue::empty());117	}118	Ok(ArrValue::range_inclusive(from, to))119}120121#[builtin]122pub fn builtin_join(sep: IndexableVal, arr: ArrValue) -> Result<IndexableVal> {123	use std::fmt::Write;124	Ok(match sep {125		IndexableVal::Arr(joiner_items) => {126			let mut out = Vec::new();127128			let mut first = true;129			for item in arr.iter() {130				let item = item?.clone();131				if let Val::Arr(items) = item {132					if !first {133						out.reserve(joiner_items.len());134						// TODO: extend135						for item in joiner_items.iter() {136							out.push(item?);137						}138					}139					first = false;140					out.reserve(items.len());141					for item in items.iter() {142						out.push(item?);143					}144				} else if matches!(item, Val::Null) {145					continue;146				} else {147					throw!("in std.join all items should be arrays");148				}149			}150151			IndexableVal::Arr(out.into())152		}153		IndexableVal::Str(sep) => {154			let mut out = String::new();155156			let mut first = true;157			for item in arr.iter() {158				let item = item?.clone();159				if let Val::Str(item) = item {160					if !first {161						out += &sep;162					}163					first = false;164					write!(out, "{item}").unwrap()165				} else if matches!(item, Val::Null) {166					continue;167				} else {168					throw!("in std.join all items should be strings");169				}170			}171172			IndexableVal::Str(out.into())173		}174	})175}176177#[builtin]178pub fn builtin_reverse(value: ArrValue) -> Result<ArrValue> {179	Ok(value.reversed())180}181182#[builtin]183pub fn builtin_any(arr: ArrValue) -> Result<bool> {184	for v in arr.iter() {185		let v = bool::from_untyped(v?)?;186		if v {187			return Ok(true);188		}189	}190	Ok(false)191}192193#[builtin]194pub fn builtin_all(arr: ArrValue) -> Result<bool> {195	for v in arr.iter() {196		let v = bool::from_untyped(v?)?;197		if !v {198			return Ok(false);199		}200	}201	Ok(true)202}203204#[builtin]205pub fn builtin_member(arr: IndexableVal, x: Any) -> Result<bool> {206	match arr {207		IndexableVal::Str(str) => {208			let x: IStr = IStr::from_untyped(x.0)?;209			Ok(!x.is_empty() && str.contains(&*x))210		}211		IndexableVal::Arr(a) => {212			for item in a.iter() {213				let item = item?;214				if equals(&item, &x.0)? {215					return Ok(true);216				}217			}218			Ok(false)219		}220	}221}222223#[builtin]224pub fn builtin_count(arr: Vec<Any>, v: Any) -> Result<usize> {225	let mut count = 0;226	for item in &arr {227		if equals(&item.0, &v.0)? {228			count += 1;229		}230	}231	Ok(count)232}