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

difftreelog

source

crates/jrsonnet-stdlib/src/arrays.rs6.8 KiBsourcehistory
1#![allow(non_snake_case)]23use jrsonnet_evaluator::{4	bail,5	function::{builtin, FuncVal},6	runtime_error,7	typed::{BoundedI32, BoundedUsize, Either2, NativeFn, Typed},8	val::{equals, ArrValue, IndexableVal},9	Either, IStr, Result, Thunk, Val,10};1112pub(crate) fn eval_on_empty(on_empty: Option<Thunk<Val>>) -> Result<Val> {13	if let Some(on_empty) = on_empty {14		on_empty.evaluate()15	} else {16		bail!("expected non-empty array")17	}18}1920#[builtin]21pub fn builtin_make_array(sz: BoundedI32<0, { i32::MAX }>, func: FuncVal) -> Result<ArrValue> {22	if *sz == 0 {23		return Ok(ArrValue::empty());24	}25	if let Some(trivial) = func.evaluate_trivial() {26		let mut out = Vec::with_capacity(*sz as usize);27		for _ in 0..*sz {28			out.push(trivial.clone())29		}30		Ok(ArrValue::eager(out))31	} else {32		Ok(ArrValue::range_exclusive(0, *sz).map(func))33	}34}3536#[builtin]37pub fn builtin_repeat(what: Either![IStr, ArrValue], count: usize) -> Result<Val> {38	Ok(match what {39		Either2::A(s) => Val::string(s.repeat(count)),40		Either2::B(arr) => Val::Arr(41			ArrValue::repeated(arr, count)42				.ok_or_else(|| runtime_error!("repeated length overflow"))?,43		),44	})45}4647#[builtin]48pub fn builtin_slice(49	indexable: IndexableVal,50	index: Option<BoundedUsize<0, { i32::MAX as usize }>>,51	end: Option<BoundedUsize<0, { i32::MAX as usize }>>,52	step: Option<BoundedUsize<1, { i32::MAX as usize }>>,53) -> Result<Val> {54	indexable.slice(index, end, step).map(Val::from)55}5657#[builtin]58pub fn builtin_map(func: FuncVal, arr: IndexableVal) -> ArrValue {59	let arr = arr.to_array();60	arr.map(func)61}6263#[builtin]64pub fn builtin_flatmap(65	func: NativeFn<((Either![String, Val],), Val)>,66	arr: IndexableVal,67) -> Result<IndexableVal> {68	use std::fmt::Write;69	match arr {70		IndexableVal::Str(str) => {71			let mut out = String::new();72			for c in str.chars() {73				match func(Either2::A(c.to_string()))? {74					Val::Str(o) => write!(out, "{o}").unwrap(),75					Val::Null => continue,76					_ => bail!("in std.join all items should be strings"),77				};78			}79			Ok(IndexableVal::Str(out.into()))80		}81		IndexableVal::Arr(a) => {82			let mut out = Vec::new();83			for el in a.iter() {84				let el = el?;85				match func(Either2::B(el))? {86					Val::Arr(o) => {87						for oe in o.iter() {88							out.push(oe?);89						}90					}91					Val::Null => continue,92					_ => bail!("in std.join all items should be arrays"),93				};94			}95			Ok(IndexableVal::Arr(out.into()))96		}97	}98}99100#[builtin]101pub fn builtin_filter(func: FuncVal, arr: ArrValue) -> Result<ArrValue> {102	arr.filter(|val| bool::from_untyped(func.evaluate_simple(&(val.clone(),), false)?))103}104105#[builtin]106pub fn builtin_filter_map(107	filter_func: FuncVal,108	map_func: FuncVal,109	arr: ArrValue,110) -> Result<ArrValue> {111	Ok(builtin_filter(filter_func, arr)?.map(map_func))112}113114#[builtin]115pub fn builtin_foldl(func: FuncVal, arr: ArrValue, init: Val) -> Result<Val> {116	let mut acc = init;117	for i in arr.iter() {118		acc = func.evaluate_simple(&(acc, i?), false)?;119	}120	Ok(acc)121}122123#[builtin]124pub fn builtin_foldr(func: FuncVal, arr: ArrValue, init: Val) -> Result<Val> {125	let mut acc = init;126	for i in arr.iter().rev() {127		acc = func.evaluate_simple(&(i?, acc), false)?;128	}129	Ok(acc)130}131132#[builtin]133pub fn builtin_range(from: i32, to: i32) -> Result<ArrValue> {134	if to < from {135		return Ok(ArrValue::empty());136	}137	Ok(ArrValue::range_inclusive(from, to))138}139140#[builtin]141pub fn builtin_join(sep: IndexableVal, arr: ArrValue) -> Result<IndexableVal> {142	use std::fmt::Write;143	Ok(match sep {144		IndexableVal::Arr(joiner_items) => {145			let mut out = Vec::new();146147			let mut first = true;148			for item in arr.iter() {149				let item = item?.clone();150				if let Val::Arr(items) = item {151					if !first {152						out.reserve(joiner_items.len());153						// TODO: extend154						for item in joiner_items.iter() {155							out.push(item?);156						}157					}158					first = false;159					out.reserve(items.len());160					for item in items.iter() {161						out.push(item?);162					}163				} else if matches!(item, Val::Null) {164					continue;165				} else {166					bail!("in std.join all items should be arrays");167				}168			}169170			IndexableVal::Arr(out.into())171		}172		IndexableVal::Str(sep) => {173			let mut out = String::new();174175			let mut first = true;176			for item in arr.iter() {177				let item = item?.clone();178				if let Val::Str(item) = item {179					if !first {180						out += &sep;181					}182					first = false;183					write!(out, "{item}").unwrap()184				} else if matches!(item, Val::Null) {185					continue;186				} else {187					bail!("in std.join all items should be strings");188				}189			}190191			IndexableVal::Str(out.into())192		}193	})194}195196#[builtin]197pub fn builtin_reverse(arr: ArrValue) -> ArrValue {198	arr.reversed()199}200201#[builtin]202pub fn builtin_any(arr: ArrValue) -> Result<bool> {203	for v in arr.iter() {204		let v = bool::from_untyped(v?)?;205		if v {206			return Ok(true);207		}208	}209	Ok(false)210}211212#[builtin]213pub fn builtin_all(arr: ArrValue) -> Result<bool> {214	for v in arr.iter() {215		let v = bool::from_untyped(v?)?;216		if !v {217			return Ok(false);218		}219	}220	Ok(true)221}222223#[builtin]224pub fn builtin_member(arr: IndexableVal, x: Val) -> Result<bool> {225	match arr {226		IndexableVal::Str(str) => {227			let x: IStr = IStr::from_untyped(x)?;228			Ok(!x.is_empty() && str.contains(&*x))229		}230		IndexableVal::Arr(a) => {231			for item in a.iter() {232				let item = item?;233				if equals(&item, &x)? {234					return Ok(true);235				}236			}237			Ok(false)238		}239	}240}241242#[builtin]243pub fn builtin_contains(arr: IndexableVal, elem: Val) -> Result<bool> {244	builtin_member(arr, elem)245}246247#[builtin]248pub fn builtin_count(arr: ArrValue, x: Val) -> Result<usize> {249	let mut count = 0;250	for item in arr.iter() {251		if equals(&item?, &x)? {252			count += 1;253		}254	}255	Ok(count)256}257258#[builtin]259pub fn builtin_avg(arr: Vec<f64>, onEmpty: Option<Thunk<Val>>) -> Result<Val> {260	if arr.is_empty() {261		return eval_on_empty(onEmpty);262	}263	Ok(Val::Num(arr.iter().sum::<f64>() / (arr.len() as f64)))264}265266#[builtin]267pub fn builtin_remove_at(arr: ArrValue, at: usize) -> Result<ArrValue> {268	let newArrLeft = arr.clone().slice(None, Some(at), None);269	let newArrRight = arr.slice(Some(at + 1), None, None);270271	Ok(ArrValue::extended(272		newArrLeft.unwrap_or(ArrValue::empty()),273		newArrRight.unwrap_or(ArrValue::empty()),274	))275}276277#[builtin]278pub fn builtin_remove(arr: ArrValue, elem: Val) -> Result<ArrValue> {279	for (index, item) in arr.iter().enumerate() {280		if equals(&item?, &elem)? {281			return builtin_remove_at(arr.clone(), index);282		}283	}284	Ok(arr)285}286287#[builtin]288pub fn builtin_flatten_arrays(arrs: Vec<ArrValue>) -> ArrValue {289	pub fn flatten_inner(values: &[ArrValue]) -> ArrValue {290		if values.len() == 1 {291			return values[0].clone();292		} else if values.len() == 2 {293			return ArrValue::extended(values[0].clone(), values[1].clone());294		}295		let (a, b) = values.split_at(values.len() / 2);296		ArrValue::extended(flatten_inner(a), flatten_inner(b))297	}298	if arrs.is_empty() {299		return ArrValue::empty();300	} else if arrs.len() == 1 {301		return arrs.into_iter().next().expect("single");302	}303	flatten_inner(&arrs)304}