--- a/crates/jrsonnet-evaluator/build.rs +++ b/crates/jrsonnet-evaluator/build.rs @@ -40,7 +40,7 @@ name == "base64" || name == "foldl" || name == "foldr" || name == "sortImpl" || name == "format" || name == "range" || name == "reverse" || name == "slice" || name == "mod" || - name == "strReplace" + name == "strReplace" || name == "map" ) }) .collect(), --- a/crates/jrsonnet-evaluator/src/builtin/mod.rs +++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs @@ -57,6 +57,7 @@ ("extVar".into(), builtin_ext_var), ("native".into(), builtin_native), ("filter".into(), builtin_filter), + ("map".into(), builtin_map), ("foldl".into(), builtin_foldl), ("foldr".into(), builtin_foldr), ("sortImpl".into(), builtin_sort_impl), @@ -294,16 +295,19 @@ 0, func: ty!(function) => Val::Func; 1, arr: ty!(array) => Val::Arr; ], { - let mut out = Vec::new(); - for item in arr.iter() { - let item = item?; - if func - .evaluate_values(context.clone(), &[item.clone()])? - .try_cast_bool("filter predicate")? { - out.push(item); - } - } - Ok(Val::Arr(out.into())) + Ok(Val::Arr(arr.filter(|val| func + .evaluate_values(context.clone(), &[val.clone()])? + .try_cast_bool("filter predicate"))?)) + }) +} + +fn builtin_map(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result { + parse_args!(context, "map", args, 2, [ + 0, func: ty!(function) => Val::Func; + 1, arr: ty!(array) => Val::Arr; + ], { + Ok(Val::Arr(arr.map(|val| func + .evaluate_values(context.clone(), &[val]))?)) }) } --- a/crates/jrsonnet-evaluator/src/val.rs +++ b/crates/jrsonnet-evaluator/src/val.rs @@ -283,6 +283,29 @@ } } + pub fn map(self, mapper: impl Fn(Val) -> Result) -> Result { + let mut out = Vec::with_capacity(self.len()); + + for value in self.iter() { + out.push(mapper(value?)?); + } + + Ok(Self::Eager(Rc::new(out))) + } + + pub fn filter(self, filter: impl Fn(&Val) -> Result) -> Result { + let mut out = Vec::with_capacity(self.len()); + + for value in self.iter() { + let value = value?; + if filter(&value)? { + out.push(value); + } + } + + Ok(Self::Eager(Rc::new(out))) + } + pub fn ptr_eq(a: &Self, b: &Self) -> bool { match (a, b) { (Self::Lazy(a), Self::Lazy(b)) => Rc::ptr_eq(a, b),