1use jrsonnet_evaluator::{2 error::{ErrorKind::RuntimeError, Result},3 function::{builtin, FuncVal},4 throw,5 typed::{BoundedI32, BoundedUsize, Either2, NativeFn, Typed},6 val::{equals, ArrValue, IndexableVal, StrValue},7 Either, IStr, Val,8};910#[builtin]11pub fn builtin_make_array(sz: BoundedI32<0, { i32::MAX }>, func: FuncVal) -> Result<ArrValue> {12 if *sz == 0 {13 return Ok(ArrValue::empty());14 }15 if let Some(trivial) = func.evaluate_trivial() {16 let mut out = Vec::with_capacity(*sz as usize);17 for _ in 0..*sz {18 out.push(trivial.clone())19 }20 Ok(ArrValue::eager(out))21 } else {22 Ok(ArrValue::range_exclusive(0, *sz).map(func))23 }24}2526#[builtin]27pub fn builtin_repeat(what: Either![IStr, ArrValue], count: usize) -> Result<Val> {28 Ok(match what {29 Either2::A(s) => Val::Str(StrValue::Flat(s.repeat(count).into())),30 Either2::B(arr) => Val::Arr(31 ArrValue::repeated(arr, count)32 .ok_or_else(|| RuntimeError("repeated length overflow".into()))?,33 ),34 })35}3637#[builtin]38pub fn builtin_slice(39 indexable: IndexableVal,40 index: Option<BoundedUsize<0, { i32::MAX as usize }>>,41 end: Option<BoundedUsize<0, { i32::MAX as usize }>>,42 step: Option<BoundedUsize<1, { i32::MAX as usize }>>,43) -> Result<Val> {44 indexable.slice(index, end, step).map(Val::from)45}4647#[builtin]48pub fn builtin_map(func: FuncVal, arr: ArrValue) -> Result<ArrValue> {49 Ok(arr.map(func))50}5152#[builtin]53pub fn builtin_flatmap(54 func: NativeFn<((Either![String, Val],), Val)>,55 arr: IndexableVal,56) -> Result<IndexableVal> {57 use std::fmt::Write;58 match arr {59 IndexableVal::Str(str) => {60 let mut out = String::new();61 for c in str.chars() {62 match func(Either2::A(c.to_string()))? {63 Val::Str(o) => write!(out, "{o}").unwrap(),64 Val::Null => continue,65 _ => throw!("in std.join all items should be strings"),66 };67 }68 Ok(IndexableVal::Str(out.into()))69 }70 IndexableVal::Arr(a) => {71 let mut out = Vec::new();72 for el in a.iter() {73 let el = el?;74 match func(Either2::B(el))? {75 Val::Arr(o) => {76 for oe in o.iter() {77 out.push(oe?);78 }79 }80 Val::Null => continue,81 _ => throw!("in std.join all items should be arrays"),82 };83 }84 Ok(IndexableVal::Arr(out.into()))85 }86 }87}8889#[builtin]90pub fn builtin_filter(func: FuncVal, arr: ArrValue) -> Result<ArrValue> {91 arr.filter(|val| bool::from_untyped(func.evaluate_simple(&(val.clone(),))?))92}9394#[builtin]95pub fn builtin_foldl(func: FuncVal, arr: ArrValue, init: Val) -> Result<Val> {96 let mut acc = init;97 for i in arr.iter() {98 acc = func.evaluate_simple(&(acc, i?))?;99 }100 Ok(acc)101}102103#[builtin]104pub fn builtin_foldr(func: FuncVal, arr: ArrValue, init: Val) -> Result<Val> {105 let mut acc = init;106 for i in arr.iter().rev() {107 acc = func.evaluate_simple(&(i?, acc))?;108 }109 Ok(acc)110}111112#[builtin]113pub fn builtin_range(from: i32, to: i32) -> Result<ArrValue> {114 if to < from {115 return Ok(ArrValue::empty());116 }117 Ok(ArrValue::range_inclusive(from, to))118}119120#[builtin]121pub fn builtin_join(sep: IndexableVal, arr: ArrValue) -> Result<IndexableVal> {122 use std::fmt::Write;123 Ok(match sep {124 IndexableVal::Arr(joiner_items) => {125 let mut out = Vec::new();126127 let mut first = true;128 for item in arr.iter() {129 let item = item?.clone();130 if let Val::Arr(items) = item {131 if !first {132 out.reserve(joiner_items.len());133 134 for item in joiner_items.iter() {135 out.push(item?);136 }137 }138 first = false;139 out.reserve(items.len());140 for item in items.iter() {141 out.push(item?);142 }143 } else if matches!(item, Val::Null) {144 continue;145 } else {146 throw!("in std.join all items should be arrays");147 }148 }149150 IndexableVal::Arr(out.into())151 }152 IndexableVal::Str(sep) => {153 let mut out = String::new();154155 let mut first = true;156 for item in arr.iter() {157 let item = item?.clone();158 if let Val::Str(item) = item {159 if !first {160 out += &sep;161 }162 first = false;163 write!(out, "{item}").unwrap()164 } else if matches!(item, Val::Null) {165 continue;166 } else {167 throw!("in std.join all items should be strings");168 }169 }170171 IndexableVal::Str(out.into())172 }173 })174}175176#[builtin]177pub fn builtin_reverse(arr: ArrValue) -> ArrValue {178 arr.reversed()179}180181#[builtin]182pub fn builtin_any(arr: ArrValue) -> Result<bool> {183 for v in arr.iter() {184 let v = bool::from_untyped(v?)?;185 if v {186 return Ok(true);187 }188 }189 Ok(false)190}191192#[builtin]193pub fn builtin_all(arr: ArrValue) -> Result<bool> {194 for v in arr.iter() {195 let v = bool::from_untyped(v?)?;196 if !v {197 return Ok(false);198 }199 }200 Ok(true)201}202203#[builtin]204pub fn builtin_member(arr: IndexableVal, x: Val) -> Result<bool> {205 match arr {206 IndexableVal::Str(str) => {207 let x: IStr = IStr::from_untyped(x)?;208 Ok(!x.is_empty() && str.contains(&*x))209 }210 IndexableVal::Arr(a) => {211 for item in a.iter() {212 let item = item?;213 if equals(&item, &x)? {214 return Ok(true);215 }216 }217 Ok(false)218 }219 }220}221222#[builtin]223pub fn builtin_count(arr: ArrValue, x: Val) -> Result<usize> {224 let mut count = 0;225 for item in arr.iter() {226 if equals(&item?, &x)? {227 count += 1;228 }229 }230 Ok(count)231}