Skip to content

Commit 7fe0652

Browse files
committed
fix: make CEL build_context generic over any (&String, &Value) iterator
build_context(), evaluate(), and evaluate_condition() now accept any type that iterates over (&String, &JsonValue) pairs — HashMap, serde_json::Map, BTreeMap, etc. This eliminates the need to clone entire JSON objects just to convert between map types. Backward-compatible: existing callers passing &HashMap compile unchanged.
1 parent de479a6 commit 7fe0652

1 file changed

Lines changed: 19 additions & 9 deletions

File tree

src/expression/evaluator.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
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

Comments
 (0)