66// License: FSL-1.1-ALv2
77// Copyright: (c) 2026 HYPERI PTY LIMITED
88
9- #![ allow( clippy:: implicit_hasher) ] // Public API uses HashMap<String, JsonValue> intentionally
10-
119//! Core CEL expression operations — compile, evaluate, validate.
1210//!
1311//! Wraps the [`cel_interpreter`] crate, enforcing the DFE expression
@@ -155,20 +153,29 @@ pub fn compile_with_config(expr: &str, config: &ProfileConfig) -> ExpressionResu
155153///
156154/// Returns an error if the expression is invalid, violates the DFE profile,
157155/// or evaluation fails (missing fields, type mismatch).
158- pub fn evaluate ( expr : & str , data : & HashMap < String , JsonValue > ) -> ExpressionResult < Value > {
156+ pub fn evaluate < ' a > (
157+ expr : & str ,
158+ data : impl IntoIterator < Item = ( & ' a String , & ' a JsonValue ) > ,
159+ ) -> ExpressionResult < Value > {
159160 let program = compile ( expr) ?;
160161 let context = build_context ( data) ?;
161162 program
162163 . execute ( & context)
163164 . map_err ( |e| ExpressionError :: Evaluation ( format ! ( "{e}" ) ) )
164165}
165166
166- /// Build a CEL [`Context`] from a JSON-compatible data map.
167+ /// Build a CEL [`Context`] from any iterable of `(key, value)` pairs.
168+ ///
169+ /// Accepts `&HashMap<String, Value>`, `&serde_json::Map<String, Value>`,
170+ /// or any other type that iterates over `(&String, &Value)`. This avoids
171+ /// unnecessary cloning when converting between map types.
167172///
168- /// Each key-value pair from the map is added as a top-level variable
169- /// in the CEL execution context. Supports all JSON types via the
170- /// `cel-interpreter` json feature (serde integration).
171- pub fn build_context ( data : & HashMap < String , JsonValue > ) -> ExpressionResult < Context < ' _ > > {
173+ /// Each key-value pair is added as a top-level variable in the CEL
174+ /// execution context. Supports all JSON types via the `cel-interpreter`
175+ /// json feature (serde integration).
176+ pub fn build_context < ' a > (
177+ data : impl IntoIterator < Item = ( & ' a String , & ' a JsonValue ) > ,
178+ ) -> ExpressionResult < Context < ' a > > {
172179 let mut context = Context :: default ( ) ;
173180 for ( key, value) in data {
174181 context. add_variable_from_value ( key, json_to_cel ( value) ) ;
@@ -188,7 +195,10 @@ pub fn build_context(data: &HashMap<String, JsonValue>) -> ExpressionResult<Cont
188195/// Non-boolean results are coerced: non-zero integers are truthy,
189196/// zero and errors are falsy.
190197#[ must_use]
191- pub fn evaluate_condition ( expr : & str , data : & HashMap < String , JsonValue > ) -> bool {
198+ pub fn evaluate_condition < ' a > (
199+ expr : & str ,
200+ data : impl IntoIterator < Item = ( & ' a String , & ' a JsonValue ) > ,
201+ ) -> bool {
192202 match evaluate ( expr, data) {
193203 Ok ( Value :: Bool ( b) ) => b,
194204 Ok ( Value :: Int ( n) ) => n != 0 ,
0 commit comments