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: IndexableVal) -> ArrValue {49 let arr = arr.to_array();50 arr.map(func)51}5253#[builtin]54pub fn builtin_flatmap(55 func: NativeFn<((Either![String, Val],), Val)>,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()))? {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(el))? {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(&(val.clone(),), false)?))93}9495#[builtin]96pub fn builtin_foldl(func: FuncVal, arr: ArrValue, init: Val) -> Result<Val> {97 let mut acc = init;98 for i in arr.iter() {99 acc = func.evaluate_simple(&(acc, i?), false)?;100 }101 Ok(acc)102}103104#[builtin]105pub fn builtin_foldr(func: FuncVal, arr: ArrValue, init: Val) -> Result<Val> {106 let mut acc = init;107 for i in arr.iter().rev() {108 acc = func.evaluate_simple(&(i?, acc), false)?;109 }110 Ok(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 135 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(arr: ArrValue) -> ArrValue {179 arr.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: Val) -> Result<bool> {206 match arr {207 IndexableVal::Str(str) => {208 let x: IStr = IStr::from_untyped(x)?;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)? {215 return Ok(true);216 }217 }218 Ok(false)219 }220 }221}222223#[builtin]224pub fn builtin_count(arr: ArrValue, x: Val) -> Result<usize> {225 let mut count = 0;226 for item in arr.iter() {227 if equals(&item?, &x)? {228 count += 1;229 }230 }231 Ok(count)232}